每天一个设计模式之Decorator模式解决类间组合爆炸问题

模式动机

Decorator模式是一种相对简单的对象结构性模式,动态和对象是个对应的关系,正如静态和类这样的对应关系,编译时能够决定的特质是静态特质,动态则表示在运行时进行操作,传统情况下使用的继承是静态的给类添加职责,动态的给对象添加职责,则是装饰者模式所要完成的事。
给类和给对象添加职责有什么不同呢
前者的灵活性要差,如果需要添加的职责很多,前者需要为每种情况都定义一个固定类,这里的每种情况指的是职责的排列组合,假如我要为一个原始类添加5个职责,则会出现5的阶乘种情况,不仅仅是类爆炸带来的繁琐,运行时对职责的修改是任意的,这就使得编译时确定的类又要在运行时频繁改变,而直接往对象中添加职责则使的结构可以灵活多变,同样的情况,我只需要额外增加5个修饰类就可以完美解决类爆炸及运行时改变的情况,这就是上述装饰者模式定义所要表达的具体含义。

模式定义

动态的给一个对象添加一些职责,就增加功能来说,该模式比生成子类更为灵活 —— GOF官方定义

装饰者模式是一种对象结构型模式,其别名也叫Wrapper(包装器,如果我英语没学错的话),话不多说,进入本类文章套路的模式结构分析,见下面哦!

模式结构分析

装饰模式结构图

装饰模式包含如下角色:

1.Component(抽象构件)

抽象构件定义了对象的接口,可以给这些对象动态增加职责(方法)。抽象构件是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务逻辑方法。它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作;

2.ConcreteComponent(具体构件)

具体构件定义了具体构件对象,也就是具体的被装饰的物品,实现了抽象构件中的声明的方法,装饰器可以给它增加额外的职责(方法),这是第一层装饰

3.Decorator(我们滴主角,抽象装饰类)

抽象装饰类是抽象构建类的子类(思考,为啥要成为它的子类??),用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的应用,也就是上图的component,通过该引用可以调用装饰之前构件对象的方法,并通过下面的子类扩展该方法,以达到装饰的目的。

4.ConcreteDecorator(具体装饰类)

具体装饰类是Decorator的子类,负责向构件添加新的职责。每一个具体装饰类都定义一些新的行为去装饰接收进来的所有的父类为Component的子类对象

系不系说的玄乎其乎的
其实!就是通过操作抽象类Component, 具体要被装饰的构建类ConcreteComponent,Decorator也继承了Component, 这样做的目的何在呢?就是在具体要被装饰的构建类ConcreteComponent每次被装饰后,装饰完的产物的父类也是Component,便于下一个装饰品去接收进来,然后进行装饰!(emmm…貌似很绕口,下面直接进入套路之撸代码吧,看完代码理解完再回头来看上面的定义就会头脑清醒甚至怀疑前几秒自己怎么那么chun^_^)

应用场景介绍:

在某咖啡店,用户可以在选择茶或者咖啡作为基础饮料,还可以任意添加红糖、奶油、冰糖等料,请用装.饰器模式实现该店饮料计费系统,以便能方便的计算不同类型的饮料价格。使用装饰模式设计该系统,绘制类图并编程实现。

//抽象构件Component
public interface Drink {

    public void markDrinking();
    public int getPrice();
}
package gz.kd.Decorater;

//具体构件类,也就是要被装饰的类
public class Coffee implements Drink{

    private int price;

    public int getPrice() {
        return price;
    }

    public Coffee(int price){
        this.price=price;
    }

    @Override
    public void markDrinking() {
        // TODO Auto-generated method stub
        System.out.println("    制作Coffee ,现在"+getPrice() +"元");
    }
}
//具体构件类,也就是要被装饰的类
public class Tea implements Drink{
    private int price;

    public int getPrice() {
        return price;
    }

    public Tea(int price){
        this.price=price;
    }

    @Override
    public void markDrinking() {
        // TODO Auto-generated method stub
        System.out.println("    制作tea ,现在"+getPrice() +"元");
    }
}
//Decorator抽象装饰类
public class drinkDecorator implements Drink{

    private Drink drink;

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

    @Override
    public void markDrinking(){
        drink.markDrinking();
    }

    @Override
    public int getPrice() {
        // TODO Auto-generated method stub
        return drink.getPrice();
    }
}
package gz.kd.Decorater;

//ConcreteDecorator(具体装饰类)装饰品,其实本身也是一个drink
public class Cream extends drinkDecorator{

    public Cream(Drink drink) {
        super(drink);
        // TODO Auto-generated constructor stub
    }


    @Override
    public void markDrinking() {
        // TODO Auto-generated method stub
        super.markDrinking();
        System.out.println("    加了奶油糖,现在"+getPrice()+"元");
    }


    @Override
    public int getPrice() {
        // TODO Auto-generated method stub
        int num =super.getPrice()+1;
        //System.out.println("price="+num);
        return num;
    }

}
public class IceSogar extends drinkDecorator{..此处省略
public class RedSogar extends drinkDecorator{..此处省略
package gz.kd.Decorater;

import java.util.Scanner;

import org.junit.Test;

public class client {

    @Test
    public void test(){
        System.out.println("*************欢迎关顾kd奶茶店*************");
        Drink drink = new Tea(2);

        drink=new IceSogar(drink);
        drink=new RedSogar(drink);
        drink=new Cream(drink);
        drink.markDrinking();

        System.out.println("*************欢迎下次光临*****************");
        System.out.println("*************收账人:kd 总金额:"+drink.getPrice()+"元********");
        //System.out.println(drink.getPrice());

    }
}

运行结果

扫描二维码关注公众号,回复: 1440026 查看本文章

通过一个个drink传递到新的装饰品中去,装饰品中又继承了Decorator,Decorator里面又维护着一个Component, 保证了每次新的装品都能接受Drink类型的对象,巧妙又优雅!


作者:KD_Y
代码片段见Git:https://gitee.com/lywe123/codes/67nfdu94c3l5rjoi2ybq176
博客:http://blog.csdn.net/weixin_36708538/article/details/78728902(转载请说明出处)
扫码关注我微信,聊点不一样的设计模式
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_36708538/article/details/78728902