装饰者模式

装饰者模式

装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

首先来分析一下为什么使用装饰者模式。例如,让一个对象添加一个新的功能,我们第一想到的就是创建一个类来继承这个类,然后添加新的功能方法。这种方式在大部分简单的场景中是可取的,可是也有一些复杂的情况。例如,各种功能之间要相互组合使用,拿手抓饼来说吧,一个手抓饼里面可以加各种食材,比如加个烤肠,加个鸡蛋等等,我以前上班的时候路过地铁站都会买一个手抓饼当早餐,既美味,又方便。平时的时候我加一个鸡蛋,一份青菜,当我发工资的时候我就阔绰一把,加一个鸡蛋,一份青菜,再加一个烤肠。可见手抓饼里的东西是可以随意组合的,假如说我们用继承的方式,我想加一个鸡蛋和一份青菜,那么我就要创建一个子类来继承手抓饼,在子类中组合鸡蛋和青菜。如果我想加一个鸡蛋一份青菜和一根烤肠,那么我就要再创建一个子类来继承手抓饼,在子类中组合鸡蛋青菜和烤肠。当然,可能月底了,没钱了,我只加一个鸡蛋,那么就又多了一种组合方式,可见,这种组合方式是特别多的,如果使用继承,那么子类将会多到爆炸。过些时候老板又推出了新的食品,可以加里脊肉了,那么多一种食品,它们的组合方式将会成几何的方式增长,显然这种场景下,使用继承的方式是不可取的,那么这个时候就可以使用装饰者模式了。

装饰模式的使用场景:

1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

装饰模式的优点:

1. 符合设计模式中的多用组合,少用继承和开闭原则
2.  通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

示例代码:

抽象手抓饼接口:

/**
 * 手抓饼抽象
 */
public interface HandPancake {
    String description(); //描述
    float price();       //价格
}

创建手抓饼实例:

public class Pancake implements HandPancake{
    private String description="煎饼";
    private float price =4;
    @Override
    public String description() {
        return description;
    }

    @Override
    public float price() {
        return price;
    }
}

抽象手抓饼组合的食材基类:

public abstract class Decorator implements HandPancake{
    protected HandPancake handPancake;
    public Decorator(HandPancake handPancake){
        this.handPancake=handPancake;
    }
}

创建鸡蛋食材实例:

public class Egg extends Decorator {
    private String description="鸡蛋";
    private float price =1;
    public Egg(HandPancake handPancake){
        super(handPancake);
    }
    @Override
    public String description() {
        return  handPancake.description()+"+"+description;
    }

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

创建青菜食材实例:

public class Greens extends Decorator {

    private String description="青菜";
    private float price =0.5f;
    public Greens(HandPancake handPancake) {
        super(handPancake);
    }

    @Override
    public String description() {
        return handPancake.description() + "+" + description;
    }

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

创建热狗食材实例:

public class HotDog extends Decorator {
    private String description="热狗";
    private float price =2;
    public HotDog(HandPancake handPancake) {
        super(handPancake);
    }

    @Override
    public String description() {
        return handPancake.description() + "+" + description;
    }

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

现在可以自由搭配买手抓饼了

/**
 * 手抓饼4元
 * 加鸡蛋1元
 * 加热狗2元
 * 加青菜0.5元
 * 上海手抓饼好贵啊,现在我都不吃了
 */
public class Test {
    public static void main(String[] args) {
        HandPancake pancake = new Pancake();    //一份手抓饼
        pancake = new Egg(pancake);             //加个鸡蛋
        pancake = new Greens(pancake);          //加点青菜
        System.out.println("你买的是:" + pancake.description() + "\t总计:" + pancake.price() + "元");
        pancake = new HotDog(pancake);          //再加根烤肠吧
        System.out.println("你买的是:" + pancake.description() + "\t总计:" + pancake.price() + "元");
    }
}

运行结果:


可以看到,使用装饰者模式,各个食材之间可以随意组合,并没有出现类的爆炸性增长。在java中,装饰者模式使用最经典的就是IO流了,大家可以去操作一下IO流,体会一下装饰者模式的特点。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值