Again we will discuss what is wrong with the given code, this time, however, with real pieces of code.
There will be shown a code, we will discuss what is good and what is bad, and at the end there will be a task to design reasonable API according to the example.
$mail = new PHPMailer();
$mail->From = "ja@muj.skvely.server.cz";
$mail->FromName = "Já";
$mail->addAddress("ty@tvuj.skvely.server.cz", "Ty");
$mail->Subject = "Spam";
$mail->isHtml(true);
$mail->Body = "<p>...</p>";
$mail->AltBody = "...";
$mail->isSmtp();
$mail->Host = "smtp.muj.skvely.server.cz";
if ($mail->Send()) {
echo"Odesláno";
} else {
echo"Neodesláno, chyba: " . $mail->ErrorInfo;
}
$mail = new PHPMailer();
$mail->From = "ja@muj.skvely.server.cz";
$mail->FromName = "Já";
$mail->AddAddress("ty@tvuj.skvely.server.cz", "Ty");
$mail->Subject = "Spam";
$mail->IsHtml(true);
$mail->Body = "<p>...</p>";
$mail->AltBody = "...";
$mail->IsSmtp();
$mail->Host = "smtp.muj.skvely.server.cz";
if ($mail->Send()) {
echo"Odesláno";
} else {
echo"Neodesláno, chyba: " . $mail->ErrorInfo;
}
There are wrong several things with the design of PHPMailer
:
From
), others using auxiliary methods
(e.g. addAddress
).
From
and FromName
could be merged into one attribute;
they represent only one mail header anyway.
isHtml
,
isSmtp
) are being used to set the attributes, and more
to that inconsistently. (isHtml
takes a parameter,
isSmtp
does not).
$mail = new PHPMailer();
$mail->From = "ja@muj.skvely.server.cz";
$mail->FromName = "Já";
$mail->AddAddress("ty@tvuj.skvely.server.cz", "Ty");
$mail->Subject = "Spam";
$mail->IsHtml(true);
$mail->Body = "<p>...</p>";
$mail->AltBody = "...";
$mail->IsSmtp();
$mail->Host = "smtp.muj.skvely.server.cz";
if ($mail->Send()) {
echo"Odesláno";
} else {
echo"Neodesláno, chyba: " . $mail->ErrorInfo;
}
The class however suffers for much serious problem: It is responsible
for two different things, constructing a mail and sending it. Sign for
that is setting attributes, which do not have any reflection in mail
header (e.g. Host
).
Better design would be to either move the "mail sending" into its own
class, or design it at least in such a way, that the call will not
contain attributes related to sending (necessary information would
be passed directly to the method Send
as parameters).
Naprogramujte použití rozumného rozhraní na posílaní e-mailu
Vytvořte jednoduché rozhraní (tj. třídu/třídy) pro práci s cestami v souborovém systému. Musí podporovat následující operace:
Jsou dány třídy File
a Directory
reprezentující soubor a adresář. Obě mají metody umožňující
základní operace s nimi (vytváření, kopírování, přesouvání, mazání,
apod.). Jaký by podle vás měl být vztah mezi těmito třídami (z pohledu
dědičnosti)?
Doprogramujte vypsaní aritmetického výrazu v postfix notaci pomocí návrhového vzoru visitor.
Doprogramujte vypsaní aritmetického výrazu v postfix a prefix notaci pomocí návrhového vzoru visitor.
The task had changed, this happens often during development. Not only we want postfix, but prefix (eventually infix, but there needs to be parentheses) as well.
The whole example is a teaser - the visitor will be doing nothing else than output values and signs (plus spaces), two different traversal of the tree needs to be implemented by two different accept methods.
The visitor has to take the data structure, on which it operates, as a blackbox.
Vector
, Stack
,
Hashtable
, Enumeration
We have come into contact with
Vector
+ Stack
and
Enumeration
+ Iterator
as an example of poorly designed classes. These classes
are part of
Java Collections Framework.
This framework is a beautiful example how bad design of
a critical API can impact negatively the whole platform
and how hard it is to fix the API. On the other hand it
is a nice example of how well designed API (after fixing)
looks. Therefore we will have a closer look at it.
If you are interested in details I recommend the document Java Collections API Design FAQ, which describes in detail choices and compromises, which had to be done by the developers of the API.
public static <T extends Object & Comparable<? super T>> T
min(Collection<? extends T> coll);
Collection
, Set
, List
,
Map
,...
AbstractCollection
, AbstractSet
,
AbstractList
, AbstractMap
,...
AbstractList.iterator
implementován pomocí
metod get
a size
, které jsou abstraktní a
definuje je až potomek
List list = Collections.synchronizedList(new ArrayList());
List list = Collections.unmodifiableList(new ArrayList());
Collections.sort
Collections.binarySearch
Collections.min
Collections.max
Collections.EMPTY_SET
Collections.EMPTY_LIST
Collections.EMPTY_MAP
RandomAccess
marker interfaceCo vypíše následující kus kódu?
public static void main(String[] args) {
Set<String> col = new HashSet<String>();
col.add("Dagi");
col.add("NkD");
for (String key : col) {
col.remove(key);
System.out.println(key);
}
}
The correct answer is "NkD" and than there will be thrown
an exception ConcurrentModificationException
.
The iterators in Java collections are fail-fast,
i.e. they are watching for collection modification while they
iterate through it. If the collection is modified, they alert
the user with an exception, which is better behavior than
nondeterministic crash somewhere in the future.
The puzzle is taken from Roman "Dagiho" Pichlík.