Innym podejściem jest zastosowanie modelu push, a nie modelu pull. Zazwyczaj trzeba różne formatek bo łamiesz hermetyzacji i mieć coś takiego:
class TruckXMLFormatter implements VehicleXMLFormatter {
public void format (XMLStream xml, Vehicle vehicle) {
Truck truck = (Truck)vehicle;
xml.beginElement("truck", NS).
attribute("name", truck.getName()).
attribute("cost", truck.getCost()).
endElement();
...
gdzie jesteś ciągnięcie danych z określonego typu do formatyzatora.
Zamiast tworzyć umywalkę danych format-agnostyk i odwrócić przepływ tak specyficzny rodzaj wypycha dane do zlewu
class Truck implements Vehicle {
public DataSink inspect (DataSink out) {
if (out.begin("truck", this)) {
// begin returns boolean to let the sink ignore this object
// allowing for cyclic graphs.
out.property("name", name).
property("cost", cost).
end(this);
}
return out;
}
...
Oznacza to, że wciąż masz dane obudowane, a ty po prostu karmienia otagowano dane do zlewu. Umywalka XML może wtedy zignorować określone części danych, może zmienić ich kolejność i zapisać kod XML. Może nawet przekazać wewnętrznie inną strategię umywalkową. Ale umywalka niekoniecznie musi dbać o typ pojazdu, tylko o to, jak przedstawiać dane w jakimś formacie. Używanie internowanych identyfikatorów globalnych zamiast ciągów wbudowanych pomaga obniżyć koszty obliczeń (ma to znaczenie tylko w przypadku pisania ASN.1 lub innych wąskich formatów).
Lepiej może zmienić nazwę IVehicleFormatterVisitor na tylko IVehicleVisitor, ponieważ jest to mechanizm bardziej ogólny niż formatowanie. – Richard
masz absolutną rację. –
Właściwe rozwiązanie. +1 –