使用装饰器设计模式为类的层次结构 [英] Using the decorator design pattern for a hierarchy of classes
问题描述
查看以下(简化)的课程层次:
Looking at the following (simplified) hierarchy of classes:
> Email (base class)
> SimpleEmail extends Email
> HtmlEmail extends Email
我需要装饰Email.send()来添加限制功能。
我需要实例化SimpleEmail,HtmlEmail或Email的其他类似的子类。
I need to decorate Email.send() to add throttling functionality. I need to instantiate SimpleEmail, HtmlEmail or other similar subclasses of Email.
这个模式应该怎么样?
我的猜测(需要纠正的)如下:
What should this pattern look like exactly? My guess (which surly needs correcting) is as follows:
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
我的大脑并没有包围我如何正确处理基类中重要的现有子类我需要增强。大多数例子简化了这一点,继承问题变得混乱。
My brain is not wrapping around how I properly deal with important existing subclasses of the base class that I need to "enhance". Most examples simplify it down to a point where the inheritance question becomes muddled.
推荐答案
这是一个简化的例子,装饰图案。类层次结构重构为 static
内部类,以便整个示例包含在一个编译单元中(如在ideone.com上所见):
Here's a simplified example of the decorator pattern. The class hierarchy is restructured as static
inner classes so that the whole example is contained in one compilation unit (as seen on 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!!!
}
}
所以这里我们有一个简单的层次结构,具有
Dog
和 Cat
子类。我们还有一个正常
装饰器 - 也是一个 Animal
- 只需将所有方法委托给另一个动物
。也就是说,它没有真正做任何有效的装饰,但是它已经准备好进行子类化,以便可以添加实际的装饰。
So here we have a simple Animal
hierarchy, with Dog
and Cat
subclasses. We also have a Normal
decorator -- also an Animal
-- that simply delegates all methods to another Animal
. That is, it doesn't really do any effective decoration, but it's ready to be subclassed so that actual decorations can be added.
我们这里只有一种方法, code> makeNoise()。然后,我们有两种实际装饰, Loud
和 Stuttering
。 (考虑 Animal
有很多方法的情况,然后正常
将是最有价值的)。
We only have one method here, makeNoise()
. We then have two kinds of actual decorations, Loud
and Stuttering
. (Consider the case where Animal
has many methods; then Normal
would be most valuable).
然后我们有一个 keepPokingIt(Animal)
方法,它采用任何 Animal
,并且将直到它 makeNoise()
之后才会执行不可争议的事情。在我们的主要
函数中,我们然后是 keepPokingIt
各种动物,装饰着各种个性特征。请注意,我们甚至可以将堆栈一个装饰放在另一个顶部。
We then have a keepPokingIt(Animal)
method, which takes ANY Animal
, and would do unmentionable things to it until it makeNoise()
. In our main
function, we then keepPokingIt
various kinds of animals, decorated with various personality traits. Note that we can even stack one decoration on top of another.
确切的实现细节可能会有所不同,但是这个简化的例子几乎捕获了
The exact implementation details may vary, but this simplified example pretty much captures the essence of the decorator pattern.
在上面的例子中, keepPokingIt
只关心它是一个 Animal
。有时你可能只想戳一个
Cat
而不是一个 Dog
,或以其他方式区分这两种类型。在这种情况下,您可以提供 NormalCat
, NormalDog
等。
In the above example, keepPokingIt
only cares that it's an Animal
. Sometimes you may want to just poke a Cat
and not a Dog
, or in other ways differentiate the two types. In those kinds of scenarios, you'd then provide NormalCat
, NormalDog
, etc.
如果您很好地设计类型层次结构,这不应该是一个问题。请记住,您不必为每个实现 class
编写装饰器,而是为每个您关心的类型编写一个装饰器。理想情况下,每个类型甚至应该是接口
,而不是具体的类
。
If you design your type hierarchy well, this should not be a problem. Remember that you don't have to write decorators for each implementation class
, but rather one for each type that you care about. Ideally, each type should even be an interface
rather than a concrete class
.
考虑 Java Collections Framework 类型层次结构,适用于例。我们有:
Consider the Java Collections Framework type hierarchy, for example. We have:
-
界面集合< E>
interface Collection<E>
- which is subinterfaced by
List<E>
,Set<E>
,Queue<E>
, etc
Guava 方便地促进了此类型层次结构上的装饰器模式实现:
Guava conveniently facilitates decorator pattern implementations on top of this type hierarchy:
-
abstract class ForwardingCollection< ; E>
- 与
抽象
子类转发列表< E> / code>
,转发集< E>
,ForwardingQueue< E>
abstract class ForwardingCollection<E>
- with
abstract
subclassesForwardingList<E>
,ForwardingSet<E>
,ForwardingQueue<E>
请注意,没有
ForwardingHashMap< K,V>
或ForwardingTreeSet< E>
。- 有效的Java第2版,第18项:首选接口抽象类
- Effective Java 2nd Edition, Item 18: Prefer interfaces to abstract classes
- Interface vs Abstract Class (general OO)
- Is it just me or are interfaces overused?
- Guava
ForwardingList
usage example
这篇关于使用装饰器设计模式为类的层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- with
- 与
- which is subinterfaced by