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

装饰者模式:动态的将新功能(装饰者,如调料)附加到对象(主体,如单品咖啡)上。在对象功能扩展方面,它比继承更有弹性。

1、以咖啡馆订单系统项目为例

咖啡种类:Espresso、ShortBlack、LongBlack、Decaf

调料:Milk、Soy、Chocolate

咖啡可以点单品,也可以和任意调料混合,最后返回咖啡价格

一个差的方案,为每一个单品和单品与调料组合,创建类,如Espresso类、ShortBlack类、Espresso&Milk类、Espresso&Milk&Soy类等,每个类里返回咖啡价格,这种方案导致类爆炸

稍微好点但是也不好的方案是,设计一个抽象超类,把调料内置到超类中,可设置添加调料方法,在单品继承自超类的实现类里,通过判断是否设置有某种调料,再计算价钱,这种设计太繁琐,而且不易扩展,如要新增一种调料,那就要改动代码,容易出错

2、装饰者模式设计:

装饰者设计模式是通过递归方式调用对象方法的,装饰者要继承自抽象主体,并且会调用抽象主体的方法,装饰者是依附于主体的

形如new Chocolate(new Chocolate(new Milk(new LongBlack))),如果返回价格调用cost方法,由于装饰者(调料)也继承自主体(Drink),而且调料.cost方法中会调用drink中的cost,一直递归调用到单品的cost方法

3、装饰者模式代码示例

//主体类
public abstract class Drink {

    private String description = "";
    private float price = 0f;

    public String getDescription() {
        return description + "-" + this.price;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    //单品中返回价格,调料中要加上单品价格
    public abstract float cost();
}
抽象主体Drink 有description和price属性来定义继承自主体的单品描述和价格,抽象方法cost用来计算单品或混合咖啡总消费
//主体中间层
public class Coffee extends Drink {
    public float cost() {
        return super.getPrice();
    }
}
设置中间层Coffee extends Drink,所有单品都继承自Coffee,单品的消费就是单品的价格
public class Decaf extends Coffee {

    public Decaf() {
        super.setDescription("Decaf");
        super.setPrice(3.0f);
    }

}
Decaf extends Coffee单品构造中初始化描述及价格
public class Espresso extends Coffee {

    public Espresso() {
        super.setDescription("Espresso");
        super.setPrice(4.0f);
    }

}
Espresso extends Coffee单品构造中初始化描述及价格
public class LongBlack extends Coffee {

    public LongBlack() {
        super.setDescription("LongBlack");
        super.setPrice(5.0f);
    }

}
LongBlack extends Coffee单品构造中初始化描述及价格
public class ShortBlack extends Coffee {

    public ShortBlack() {
        super.setDescription("ShortBlack");
        super.setPrice(6.0f);
    }

}
ShortBlack extends Coffee单品构造中初始化描述及价格
//装饰者中间层
public class Decorator extends Drink {

    //可以是单品也可以是被包装过的单品
    private Drink drink;

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

    public float cost() {
        //返回装饰者(调料)的价格+单品或者被包装过的单品的价格(被包装过的单品就是继承自装饰者的调料)
        return super.getPrice() + drink.cost();
    }

    @Override
    public String getDescription() {
        return super.getDescription() + "&&" + drink.getDescription();
    }
}
装饰者中间层Decorator extends Drink,装饰者依附于主体或混合主体,所以要有主体或混合主体对象,其cost总消费为装饰者价格加上主体或混合主体消费,描述为装饰者描述和主体描述
public class Chocolate extends Decorator {
    public Chocolate(Drink drink) {
        super(drink);
        super.setDescription("Chocolate");
        super.setPrice(3.0f);
    }
}
Chocolate extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格
public class Milk extends Decorator {
    public Milk(Drink drink) {
        super(drink);
        super.setDescription("Milk");
        super.setPrice(2.0f);
    }
}
Milk extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格
public class Soy extends Decorator {
    public Soy(Drink drink) {
        super(drink);
        super.setDescription("Soy");
        super.setPrice(1.0f);
    }
}
Soy extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格

测试代码:

public class CoffeeBar {

    public static void main(String[] args) {
        Drink order;
        order = new Decaf();
        System.out.println("order price:" + order.cost());
        System.out.println("order desc:" + order.getDescription());

        System.out.println("***********************************");

        order = new LongBlack();
        order = new Milk(order);
        order = new Chocolate(order);
        order = new Chocolate(order);
        System.out.println("order2 price:" + order.cost());
        System.out.println("order2 desc:" + order.getDescription());
    }

}
应用测试代码CoffeeBar
原文地址:https://www.cnblogs.com/hujiapeng/p/8059347.html