代码之家  ›  专栏  ›  技术社区  ›  Alex Baranosky

何时使用装饰图案?

  •  85
  • Alex Baranosky  · 技术社区  · 17 年前

    谢谢。

    10 回复  |  直到 10 年前
        1
  •  98
  •   Top-Master OMG Ponies    4 年前

    这 Decorator object class 和/或子类。通过子类化对象的类很容易为整个对象类添加功能,但不可能以这种方式扩展单个对象。使用装饰器模式,您可以向单个对象添加功能,而不修改其他对象。

    FileReader       frdr = new FileReader(filename);
    LineNumberReader lrdr = new LineNumberReader(frdr);
    

    前面的代码创建了一个阅读器-- lrdr --它从文件中读取并跟踪行号。第1行创建了一个文件读取器( frdr )第2行添加了行号跟踪。

        2
  •  45
  •   Charlie Salts    17 年前

        3
  •  39
  •   Kaleb Brasee    17 年前

    public Command receive(Request request);
    public Response execute(Command command);
    public void respond(Response response);
    

    基本上,CommandProcessor接收请求并创建正确的命令,执行命令并创建适当的响应,然后发送响应。当我想添加计时并记录它时,我创建了一个TimerDecoror,它使用现有的CommandProcessor作为其组件。TimerDecorator实现了CommandProcessor接口,但只是添加了计时,然后调用其目标,即真正的CommandProcessor。大致如下:

    public class TimerDecorator implements CommandProcessor {
       private CommandProcessor target;
       private Timer timer;
    
       public TimerDecorator(CommandProcessor processor) {
          this.target = processor;
          this.timer = new Timer();
       }
    
       public Command receive(Request request) {
          this.timer.start();
          return this.target.receive(request);
       }
    
       public Response execute(Command command) {
          return this.target.execute(command);
       }
    
       public void respond(Response response) {
          this.target.response(response);
          this.timer.stop();
          // log timer
       }
    
    }
    

        4
  •  17
  •   Ravindra babu    3 年前

    Decorator 模式在运行时动态地改变对象的功能。

    计算可能包含多种口味的饮料的价格。

    abstract class Beverage {
        protected String name;
        protected int price;
        public Beverage(){
            
        }
        public  Beverage(String name){
            this.name = name;
        }
        public void setName(String name){
            this.name = name;
        }
        public String getName(){
            return name;
        }
        protected void setPrice(int price){
            this.price = price;
        }
        protected int getPrice(){
            return price;
        }
        protected abstract void decorateBeverage();
        
    }
    class Tea extends Beverage{
        public Tea(String name){
            super(name);
            setPrice(10);
        }
        public void decorateBeverage(){
            System.out.println("Cost of:"+ name +":"+ price);
            // You can add some more functionality
        }
    }
    class Coffee extends Beverage{
        public Coffee(String name){
            super(name);
            setPrice(15);
        }
        public void decorateBeverage(){
            System.out.println("Cost of:"+ name +":"+ price);
            // You can add some more functionality
        }   
    }
    abstract class BeverageDecorator extends Beverage {
        protected Beverage beverage;
        public BeverageDecorator(Beverage beverage){    
            this.beverage = beverage;   
            setName(beverage.getName()+"+"+getDecoratedName());
            setPrice(beverage.getPrice()+getIncrementPrice());
        }
        public void decorateBeverage(){
            beverage.decorateBeverage();
            System.out.println("Cost of:"+getName()+":"+getPrice());
        }   
        public abstract int getIncrementPrice();
        public abstract String getDecoratedName();
    }
    class SugarDecorator extends BeverageDecorator{
        public SugarDecorator(Beverage beverage){
            super(beverage);
        }
        public void decorateBeverage(){
            super.decorateBeverage();
            decorateSugar();        
        }
        public void decorateSugar(){
            System.out.println("Added Sugar to:"+beverage.getName());
        }
        public int getIncrementPrice(){
            return 5;
        }
        public String getDecoratedName(){
            return "Sugar";
        }
    }
    class LemonDecorator extends BeverageDecorator{
        public LemonDecorator(Beverage beverage){
            super(beverage);
        }
        public void decorateBeverage(){
            super.decorateBeverage();
            decorateLemon();    
        }
        public void decorateLemon(){
            System.out.println("Added Lemon to:"+beverage.getName());       
        }
        public int getIncrementPrice(){
            return 3;
        }
        public String getDecoratedName(){
            return "Lemon";
        }
    }
    
    public class VendingMachineDecorator {  
        public static void main(String args[]){
            Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
            beverage.decorateBeverage();
            beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
            beverage.decorateBeverage();
        }
    }
    

    输出:

    Cost of:Assam Tea:10
    Cost of:Assam Tea+Lemon:13
    Added Lemon to:Assam Tea
    Cost of:Assam Tea+Lemon+Sugar:18
    Added Sugar to:Assam Tea+Lemon
    Cost of:Cappuccino:15
    Cost of:Cappuccino+Lemon:18
    Added Lemon to:Cappuccino
    Cost of:Cappuccino+Lemon+Sugar:23
    Added Sugar to:Cappuccino+Lemon
    

    此示例在向饮料中添加多种口味后计算自动售货机中饮料的成本。

    在上述示例中:

    茶的成本=10,柠檬=3,糖=5。如果你做糖+柠檬+茶,它的价格是18。

    咖啡成本=15,柠檬=3,糖=5。如果你做糖+柠檬+咖啡,它的价格是23

    通过对两种饮料(茶和咖啡)使用相同的装饰器,减少了子类的数量。在没有Decorator模式的情况下,您应该为不同的组合设置不同的子类。

    SugarLemonTea
    SugarTea
    LemonTea
    
    SugarLemonCapaccuino
    SugarCapaccuino
    LemonCapaccuino
    

    等等

    对于这两种饮料,子类的数量都有所减少。

    Use Cases and Examples of GoF Decorator Pattern for IO

        5
  •  8
  •   Josiah Yoder DWS    7 年前

    这个装饰器很简单,但非常强大。它是实现关注点分离的关键,也是开放封闭原则的重要工具。以订购产品为例:

    IOrderGateway
    {
        void PlaceOrder(Order order);
    {
    

    主要实施: AmazonAffiliateOrderGateway

    可能的装饰师可能是:

    • IncrementPerformanceCounterOrderGateway
    • QueueOrderForLaterOnTimeoutOrderGateway
    • EmailOnExceptionOrderGateway
    • InterceptTestOrderAndLogOrderGateway

    here 展示了一个装饰器,它在完成订单时保存使用礼品卡创建的订单的联系人:

    class OrderWithGiftCardGateway extends OrderGatewayDecorator
    {
        ...
    
        public function createOrder(CreateOrderRequest $order)
        {
            if ($this->containsGiftCard($order))
            {
                $this->addContactToFolder($order);
            }
    
            return parent::createOrder($order);
        }
    }
    
        6
  •  4
  •   DxAlpha    10 年前
    1. 对于可以撤销的责任。
        7
  •  1
  •   Lunatic    4 年前

    定义:

    动态地为对象附加其他职责。装饰器为扩展功能提供了一种灵活的子类化替代方案。

    这种模式表示,类必须关闭以进行修改,但打开以进行扩展,可以在不干扰现有功能的情况下添加新功能。当我们想向特定对象而不是整个类添加特殊功能时,这个概念非常有用。在这种模式中,我们使用对象组合而不是继承的概念。

    public abstract class Decorator<T> {
        private T t;
    
        public void setTheKernel(Supplier<? extends T> supplier) {
            this.t = supplier.get();
        }
    
        public T decorate() {
            return Objects.isNull(t) ? null : this.t;
        }
    
    }
    

    实施

    public interface Repository {
        void save();
    }
    
    public class RepositoryImpl implements Repository{
        @Override
        public void save() {
            System.out.println("saved successfully");
        }
    }
    
    public class EnhancedRepository<T> extends Decorator<T> {
        public void enhancedSave() {
            System.out.println("enhanced save activated");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            EnhancedRepository<Repository> enhanced = new EnhancedRepository<>();
            enhanced.setTheKernel(RepositoryImpl::new);
            enhanced.enhancedSave();
            enhanced.decorate().save();
        }
    }
    
        8
  •  0
  •   Ayushmati    7 年前

    这些子类继承自Stream类,还包含Stream类的一个实例。

    阅读更多 here

        9
  •  0
  •   CodeRanger    6 年前

    当你想向一个类/对象添加多个功能,并且想在需要时灵活地添加它们时,Decorator会派上用场。你可以扩展基类并添加你想要的更改,但这样你会想出很多让你大吃一惊的子类。但是使用decorator,您可以进行所需的更改,但仍然有一个简单易懂的流程。 例如,你有一个文件流,在一个用例中,你想加密它,然后压缩它,然后记录它,最后用它做一些花哨的事情。然后在另一个类中,你决定做其他事情。你想转换它,然后加密它,然后得到时间,bluh,bluh。在其他课程中,你还有另一个流程。 如果你想使用继承,你必须创建至少3个子类,如果需要任何其他要求,你必须添加更多的子类,在这种情况下(Stream),你最终会因为微小的变化而得到几十个子类。

    class EncryptZipLogStream{}
    class ConvertEncryptTimeStream{}
    class MoreStreamProcess{}
    class OtherMoreStreamProcess{}
    ...
    

    在每个用例中,你必须记住需要什么类,并尝试使用它。 但是,想象一下,你使用了组合而不是继承,并且每个Stream进程都有装饰器类,你可以很容易地组合你想要的包装器,并以最少的努力和最大的简单性拥有任何想要的进程。

    class WhereIWannaUseUseCaseOne {
        EncryptStream(ZipStream(LogStream(FileStream("file name)))));
        // rest of the code to use the combines streams.
    }
    

    然后你提出了另一个用例:

    class WhereIWannaUseUseCaseSecond {
        ConvertStream(TimeStream(LogStream(FileStream("file name)))));
        // rest of the code to use the combines streams.
    }
    

        10
  •  -1
  •   Mariano LEANCE    6 年前

    我不得不更新一个在项目中大量使用的类,但该类在库中,源代码在地下世界丢失了。

    当负责任地使用时,这是一个非常有用的模式。

    这个特殊的案例启发了我 this video 在那里我解释了模式。

    推荐文章