zoukankan      html  css  js  c++  java
  • 设计模式之装饰者模式

     情景:

    你是一个咖啡店老板,你会做很多种咖啡。

    首先有一个超类,饮料类。

    咖啡可以加很多种调料,就假设是A,B,C……

    那么你会有AB型的,AC型,BC型,A型的,B型,C型,ABC型的咖啡,那么你需要有六种具体子类。

    如果有n种调料,你就要有(2^n-1)种具体子类有木有啊!!!

    同时,如果,你添加了一种调料或者改变一种调料!!!会死人呐有木有!!!

    怎么办?? 可以考虑使用组合(compisition)和委托(delegation)。

    设计原则:类应该对扩展开放,对修改关闭。

    装饰者模式

    以饮料为主体,然后在运行时,以调料来装饰(decorate)饮料。

    设饮料价格是X,加了调料A,可以用A把X包装起来A(X),又加了调料B,再用B把A(x)包装起来,B(A(X))。

    • 装饰着和被装饰者具有相同的超类型。
    • 你可以用一个或多个装饰者包装一个对象。
    • 既然装饰者和被装饰者对象具有相同的超类型,所以在任何需要原始对象(被包装的)的场合,都可以用装饰过的对象代替它。
    • 装饰者可以在所委托被装饰者的行为之前/或之后,加上自己的行为,已达到特定的目的。
    • 对象可以在任何时候被装饰,可以在运行时动态地,不限量地用你喜欢的装饰者来装饰对象。

    装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

    类图:

    解决最开始的咖啡问题~~

    首先饮料类:

    public abstract class Beverage {
        String description = "Unknown Beverage";
        
        public String getDescription() {
            return description;
        }
        
        public abstract double cost();
    }

    然后是两种具体的饮料

    public class Espresso extends Beverage {
        public Espresso() {
            description = "Espresso";
        }
        @Override
        public double cost() {
            return 1.99;
        }
    }
    public class HouseBlend extends Beverage {
        public HouseBlend() {
            description = "House Blend Coffee";
        }
        @Override
        public double cost() {
            return 0.89;
        }
    }

    调料抽象类:

    public abstract class CondimentDecorator extends Beverage {
        public abstract String getDescription();
    }

    具体调料类(包装类):

    摩卡

    public class Mocha extends CondimentDecorator {
        
        Beverage beverage;        // 被装饰者
        
        public Mocha(Beverage beverage) {
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + ", Mocha";
        }
    
        @Override
        public double cost() {
            return .20 + beverage.cost();
        }
        
    }

    豆浆

    public class Soy extends CondimentDecorator {
        
        Beverage beverage;        // 被装饰者
        
        public Soy(Beverage beverage) {
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + ", Soy";
        }
    
        @Override
        public double cost() {
            return .15 + beverage.cost();
        }
        
    }

    好了,测试一下:

    public class StarBuzzCoffee {
        public static void main(String[] args) {
            Beverage beverage = new Espresso();     // 一杯Espresso 不加调料
            System.out.println(beverage.getDescription() + " $" + beverage.cost());
            
            Beverage beverage2 = new HouseBlend();    // 一杯HouseBlend 加摩卡  加豆浆
            beverage2 = new Mocha(beverage2);
            beverage2 = new Soy(beverage2);
            System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
        }
    }

    输出:

    Espresso $1.99
    House Blend Coffee, Mocha, Soy $1.24

    Java的io包中使用了装饰者模式。

     

     编写自己的Java IO装饰者

    import java.io.FilterInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class LowerCaseInputStream extends FilterInputStream {
        public LowerCaseInputStream(InputStream in) {
            super(in);
        }
        
        public int read() throws IOException {
            int c = super.read();
            return (c == -1 ? c : Character.toLowerCase((char)c));
        }
        
        public int read(byte[] b, int offset, int len) throws IOException {
            int result = super.read(b, offset, len);
            for (int i = offset; i < offset + result; i++) {
                b[i] = (byte)Character.toLowerCase((char)b[i]);
            }
            return result;
        }
    }

    测试一下:(使用了try-with-resources)

    public class InputTest {
        public static void main(String[] args) {
            int c;
            try (
                InputStream in = new LowerCaseInputStream(
                        new LowerCaseInputStream(
                                new FileInputStream("test.txt")));
            ) {
                while ((c = in.read()) > 0) {
                    System.out.print((char)c);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    test.txt内容: I know the Decorator Pattern therefore I RULE! 

    输出: i know the decorator pattern therefore i rule! 

    装饰者模式的缺点:

    会产生大量的类。实例化的时候会很复杂。

  • 相关阅读:
    15. DML, DDL, LOGON 触发器
    5. 跟踪标记 (Trace Flag) 834, 845 对内存页行为的影响
    4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志
    14. 类似正则表达式的字符处理问题
    01. SELECT显示和PRINT打印超长的字符
    3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息
    2. 跟踪标记 (Trace Flag) 3604, 3605 输出DBCC命令结果
    1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
    0. 跟踪标记 (Trace Flag) 简介
    SpringBoot + Redis + Shiro 实现权限管理(转)
  • 原文地址:https://www.cnblogs.com/wenruo/p/6536570.html
Copyright © 2011-2022 走看看