将装饰器设计模式用于类的层次结构

Dav*_*rks 2 java design-patterns decorator

查看以下(简化)类的层次结构:

>     Email (base class) 
>     SimpleEmail extends Email
>     HtmlEmail extends Email
Run Code Online (Sandbox Code Playgroud)

我需要修饰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
Run Code Online (Sandbox Code Playgroud)

我的大脑并没有围绕我如何正确处理我需要"增强"的基类的重要现有子类.大多数示例将其简化为继承问题变得混乱的程度.

pol*_*nts 9

这是装饰器模式的简化示例.类层次结构重构为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!!!        
    }
}
Run Code Online (Sandbox Code Playgroud)

所以在这里我们有一个简单Animal的层次结构,与DogCat子类.我们还有一个Normal装饰器 - 也是一个Animal- 只是将所有方法委托给另一个Animal.也就是说,它并没有真正做任何有效的装饰,但它已准备好进行子类化,以便可以添加实际的装饰.

我们这里只有一种方法makeNoise().然后我们有两种实际装饰,LoudStuttering.(考虑Animal具有许多方法的情况;然后Normal将是最有价值的).

然后我们有一个keepPokingIt(Animal)方法,它采取任何方式 Animal,并将做它不可告知的事情,直到它makeNoise().在我们的main功能中,我们接着keepPokingIt各种各样的动物,装饰着各种个性特征.请注意,我们甚至可以将一个装饰堆叠在另一个上面.

确切的实现细节可能会有所不同,但这个简化的示例几乎捕获了装饰器模式的本质.


另一个例子:ForwardingCollectionGuava的层次结构

在上面的例子中,keepPokingIt只关心它是一个Animal.有时您可能只想戳一个Cat而不是一个Dog,或者以其他方式区分这两种类型.在这些类型的场景中,你会再提供NormalCat,NormalDog等等.

如果你很好地设计你的类型层次结构,这应该不是问题.请记住,您不必为每个实现编写装饰器class,而是为您关心的每种类型编写装饰器.理想情况下,每种类型甚至应该是一种interface而不是具体的class.

例如,考虑Java Collections Framework类型层次结构.我们有:

Guava方便地在这种类型层次结构上促进装饰器模式实现:

请注意,没有ForwardingHashMap<K,V>,或者a ForwardingTreeSet<E>.反正可能没有必要.

也可以看看

  • Effective Java 2nd Edition,Item 18:首选接口到抽象类

相关问题