JAVA23种设计模式之装饰者模式

  1. 装饰者模式:
    又名包装模式,顾名思义,就是通过一定的方式,包装一个对象。给他附加上各种不同的属性,但是又不改变被包装对象的结构。通过定义可以看出,装饰者模式其实是子类继承的一种替代方式。
  2. 装饰者模式包含的角色:
  • 被装饰对象的抽象角色: 给出一个抽象类或者接口,可以动态的给对象增加属性,规范对象属性的内容。
  • 具体被装饰对象角色: 定义一个具体的对象,用于接受附加的属性。对于开发来说就是定义一个具体的类,用户实现不同的方法
  • 抽象装饰者角色: 维护指向被装饰对象的抽象角色的引用,定义与被装饰对象的抽象角色一致的接口,换句话说就是要继承或者实现被装饰对象抽象角色的方法。
  • 具体装饰者角色: 继承或实现抽象装饰者角色,并且包含具体属性的内容,也就是开发中的方法实现。
  1. 装饰者模式示意图:

在这里插入图片描述
引用自《由装饰者模式来深入理解Java I/O整体框架

  1. 装饰者模式的代码示例:
    场景:计算奶茶店的奶茶添加不同配料的价格。
  • 被装饰对象的抽象角色:
public interface Drink {

    String name();

    float price();
}
  • 具体被装饰对象角色:
public class Tea implements Drink {

    @Override
    public String name() {
        return "only Tea";
    }

    @Override
    public float price() {
        return 10;
    }
}
  • 抽象装饰者角色:
public abstract class Supplement implements Drink {

    //传入一个被装饰对象
    private Drink drink;

    public Supplement(Drink drink) {
        this.drink = drink;
    }

    @Override
    public String name(){
        return drink.name();
    }

    @Override
    public float price() {
        return drink.price();
    }
}
  • 具体装饰者角色:
    装饰角色:珍珠
public class Bubble extends Supplement {

    public Bubble(Drink drink) {
        super(drink);
    }

    @Override
    public String name() {
        return super.name()+">>>Add Bubble";
    }

    @Override
    public float price() {
        return super.price()+5;
    }
}

装饰角色:布丁

public class Pudding extends Supplement {

    public Pudding(Drink drink) {
        super(drink);
    }

    @Override
    public String name() {
        return super.name()+">>>>Add Pudding";
    }

    @Override
    public float price() {
        return super.price() + 3;
    }
}

装饰角色:牛奶

public class Milk extends Supplement {

    public Milk(Drink drink) {
        super(drink);
    }

    @Override
    public String name() {
        return super.name()+">>>Add Milk!!!";
    }

    @Override
    public float price() {
        return super.price()+5;
    }
}
  • 测试主方法:
public class Main {
    public static void main(String[] args) {

        //初始化被装饰对象
        Drink tea = new Tea();

        //开始装饰
        tea = new Pudding(tea);
        tea = new Milk(tea);

        System.out.println("添加配料表:"+tea.name()+"||最终价格:"+tea.price() );
    }
}

总结:
通过以上代码,可以看出装饰者模式具有以下优点:

  1. 装饰者模式和继承都具有扩展对象的功能,但是相对来说,装饰者模式相比继承来说更加灵活,装饰者模式可以在需要的情况下,给对象添加一个属性或者取消一个属性。
  2. 装饰者更像是乐高积木,给你各种形状,你可以自己拼成不同的建筑或者其他内容。
    装饰者模式的缺点:
    由于排列组合会产生很多的对象之间的关系,导致后期处理bug时,查找对象之间的关系会很麻烦。

JAVA内置的装饰者模式:
在JAVA中最能体现装饰者模式的就是JAVA的I/O流的操作,这里使用极客学院的JAVA示例代码作为展示。
需求:将输入的字符或者文件以大写的形式输出。
UpperCaseInputStream类:

public class UpperCaseInputStream extends FilterInputStream {
    /**
     * Creates a <code>FilterInputStream</code>
     * by assigning the  argument <code>in</code>
     * to the field <code>this.in</code> so as
     * to remember it for later use.
     *
     * @param in the underlying input stream, or <code>null</code> if
     *           this instance is to be created without an underlying stream.
     */
    protected UpperCaseInputStream(InputStream in) {
        //输入被装饰者
        super(in);
    }

    @Override
    public int read() throws IOException {
        int c =  super.read();
        return c==-1?c:Character.toUpperCase((char)c);
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result =  super.read(b, off, len);
        for (int i = 0; i < result; i++) {
            b[i] = (byte) Character.toUpperCase((char)b[i]);
        }
        return result;
    }
}

测试方法类:

public class Mian {

    public static void main(String[] args) throws IOException {
        int c;
        InputStream io = new UpperCaseInputStream(new BufferedInputStream(new FileInputStream("G:\\test.txt")));
        while ((c=io.read())>=0){
            System.out.print((char)c);
        }
    }
}
  • 被装饰对象的抽象角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。

  • 具体被装饰对象角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。

  • 抽象装饰者角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。

  • 具体装饰者角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值