[英]Using the decorator design pattern for a hierarchy of classes
查看以下(簡化)類的層次結構:
> Email (base class)
> SimpleEmail extends Email
> HtmlEmail extends Email
我需要修飾Email.send()以添加限制功能。 我需要實例化SimpleEmail,HtmlEmail或其他類似的Email子類。
這個模式到底應該是什么樣的? 我的猜測(需要糾正)如下:
class abstract EmailDecorator
-> Define a constructor: EmailDecorator(Email component)
-> Implements all methods of Email and passes values through to component
-> Adds functionality to send() method
class SimpleEmailDecorator extends EmailDecorator
-> Define a constructor: SimpleEmailDecorator(SimpleEmail component)
-> Implement all methods of SimpleEmail and pass through to component
class HtmlEmailDirector extends EmaiDecorator
-> Same as SimpleEmailDecorator
我的大腦並沒有圍繞我如何正確處理我需要“增強”的基類的重要現有子類。 大多數示例將其簡化為繼承問題變得混亂的程度。
這是裝飾器模式的簡化示例。 類層次結構被重構為static
內部類,因此整個示例包含在一個編譯單元中( 如ideone.com上所示 ):
public class AnimalDecorator {
static abstract class Animal {
public abstract String makeNoise();
}
static class Dog extends Animal {
@Override public String makeNoise() { return "woof"; }
}
static class Cat extends Animal {
@Override public String makeNoise() { return "meow"; }
}
static class Normal extends Animal {
protected final Animal delegate;
Normal(Animal delegate) { this.delegate = delegate; }
@Override public String makeNoise() {
return delegate.makeNoise();
}
}
static class Loud extends Normal {
Loud(Animal delegate) { super(delegate); }
@Override public String makeNoise() {
return String.format("%S!!!", delegate.makeNoise());
}
}
static class Stuttering extends Normal {
Stuttering(Animal delegate) { super(delegate); }
@Override public String makeNoise() {
return delegate.makeNoise().replaceFirst(".", "$0-$0-$0-$0");
}
}
public static void keepPokingIt(Animal a) {
// let's skip the details for now...
System.out.println(a.makeNoise());
}
public static void main(String[] args) {
keepPokingIt(new Cat());
// meow
keepPokingIt(new Stuttering(new Dog()));
// w-w-w-woof
keepPokingIt(new Loud(new Cat()));
// MEOW!!!
keepPokingIt(new Loud(new Stuttering(new Dog())));
// W-W-W-WOOF!!!
}
}
所以這里我們有一個簡單的Animal
層次結構,包含Dog
和Cat
子類。 我們還有一個Normal
裝飾器 - 也是一個Animal
- 它只是將所有方法委托給另一個Animal
。 也就是說,它並沒有真正做任何有效的裝飾,但它已准備好進行子類化,以便可以添加實際的裝飾。
我們這里只有一個方法, makeNoise()
。 然后我們有兩種實際的裝飾, Loud
和Stuttering
。 (考慮Animal
有很多方法的情況;那么Normal
會是最有價值的)。
然后我們有一個keepPokingIt(Animal)
方法,該方法接受任何 Animal
,並且在makeNoise()
之前makeNoise()
它做任何 makeNoise()
事情。 在我們的main
功能中,我們隨后keepPokingIt
各種各樣的動物,裝飾着各種個性特征。 請注意,我們甚至可以將一個裝飾堆疊在另一個上面。
確切的實現細節可能會有所不同,但這個簡化的示例幾乎捕獲了裝飾器模式的本質。
ForwardingCollection
層次結構 在上面的例子中, keepPokingIt
只關心它是一個Animal
。 有時您可能只想戳Cat
而不是Dog
,或者以其他方式區分這兩種類型。 在這些場景中,您將提供NormalCat
, NormalDog
等。
如果你很好地設計你的類型層次結構,這應該不是問題。 請記住,您不必為每個實現class
編寫裝飾器,而是為您關心的每種類型編寫裝飾器。 理想情況下,每種類型甚至應該是一個interface
而不是一個具體的class
。
例如,考慮Java Collections Framework類型層次結構。 我們有:
Guava方便地在這種類型層次結構上促進裝飾器模式實現:
abstract class ForwardingCollection<E>
abstract
subclasses ForwardingList<E>
, ForwardingSet<E>
, ForwardingQueue<E>
abstract class ForwardingMap<K,V>
請注意,沒有ForwardingHashMap<K,V>
或ForwardingTreeSet<E>
。 反正可能沒有必要。
如果子類有其他方法,並且您希望通過裝飾器訪問這些方法,則必須為每個子類編寫單獨的裝飾器。 對於您的特殊問題,我建議另一種解決方案。 從Email
-class中刪除send
-method並創建一個負責發送電子郵件的新類Mailer
:
class Mailer {
public void send(Email mail) {
// get required info from mail
String recipents = mail.getRecipents()
String subject = mail.getSubject()
String content = mail.getContent()
// do stuff with all the information
}
}
這樣,您可以使用不同的方式發送電子郵件與所有類型的電子郵件。
您需要SimpleEmail或HtmlEmail的特殊方法嗎?
如果沒有,那么非抽象的EmailDecorator就足夠了。 如果Email,SimpleEmail或HtmlEmail實現了某些接口,那么你也應該真正實現它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.