• 设计模式之装饰者模式


     情景:

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

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

    咖啡可以加很多种调料,就假设是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! 

    装饰者模式的缺点:

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

  • 相关阅读:
    DRF内置限流组件之自定义限流机制
    DRF内置权限组件之自定义权限管理类
    DRF内置认证组件之自定义认证系统
    java基础(15)--多态
    java基础(13)--静态变量、静态代码块、实例代码块
    java基础(12)--static变量/方法 与 无 static的变量/方法的区别
    java基础(11)--封装
    java基础(10)--空指针异常
    java基础(9)--方法重载
    java基础(8)--键盘输入
  • 原文地址:https://www.cnblogs.com/wenruo/p/6536570.html
Copyright © 2020-2023  润新知