java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷????
halo各位小伙伴们,今天我们一起来了解一下装饰者模式,首先还是先进入下面的案例,话不多说,我们开始吧!
蜜雪**是规模比较大的连锁饮品店,因为分店开的越来越多,扩张速度越来越快,他们准备更新订单系统,以合乎他们的饮料供应要求。 他们原先的类设计是这样的……
蜜雪**是规模比较大的连锁饮品店,因为分店开的越来越多,扩张速度越来越快,他们准备更新订单系统,以合乎他们的饮料供应要求。
他们原先的类设计是这样的……
但是在购买饮品时,有些顾客会加一些配料,什么奶盖,布丁,椰果,巧克力等等,而蜜雪**呢也会根据配料的不同计算价格,所以 订单必须得考虑到这些配料的价格等。
但是在购买饮品时,有些顾客会加一些配料,什么奶盖,布丁,椰果,巧克力等等,而蜜雪**呢也会根据配料的不同计算价格,所以
订单必须得考虑到这些配料的价格等。
这是他们的第一次尝试...
每个cost都得计算出奶茶+订单上所有的配料的价格,很明显这是个噩梦一样的存在。。。
这时候有一个人提出了为什么不用一些变量进行相关配料的约束呢? 那么我们根据他的思路进行程序的改造,下面是新的程序以及类图
public class Drinks { public String description; public boolean Milk = false; public boolean Pudding = false; public boolean MilkCaps = false; public boolean Coconut = false; //...other ingredient public float cost() { if (hasMilk() || hasMilkCaps()) { return 1; } else if (hasCoconut()) { return 2; } else if (hasPudding()) { return 3; } return 0; } public void setDescription(String description) { this.description = description; } public String getDescription() { return description; } public boolean hasMilk() { return Milk; } public boolean hasPudding() { return Pudding; } public boolean hasMilkCaps() { return MilkCaps; } public boolean hasCoconut() { return Coconut; } public void setHasMilk(boolean hasMilk) { this.Milk = hasMilk; } public void setHasPudding(boolean hasPudding) { this.Pudding = hasPudding; } public void setHasMilkCaps(boolean hasMilkCaps) { this.MilkCaps = hasMilkCaps; } public void setHasCoconut(boolean hasCoconut) { this.Coconut = hasCoconut; } //other set options...}//coffee with milk-cuppublic class Coffee extends Drinks { @Override public void setDescription(String description) { super.setDescription(description); } @Override public float cost() { return super.cost()+3; }}//test mainpublic class Main { public static void main(String[] args) { Drinks coffee = new Coffee(); coffee.setDescription("coffee with milk-cup"); coffee.setHasMilkCaps(true); System.out.println("商品:"+coffee.getDescription() + " 价格:"+coffee.cost()); }}//运行结果商品:coffee with milk-cup 价格:4.0Process finished with exit code 0
public class Drinks {
public String description;
public boolean Milk = false;
public boolean Pudding = false;
public boolean MilkCaps = false;
public boolean Coconut = false;
//...other ingredient
public float cost() {
if (hasMilk() || hasMilkCaps()) {
return 1;
} else if (hasCoconut()) {
return 2;
} else if (hasPudding()) {
return 3;
}
return 0;
public void setDescription(String description) {
this.description = description;
public String getDescription() {
return description;
public boolean hasMilk() {
return Milk;
public boolean hasPudding() {
return Pudding;
public boolean hasMilkCaps() {
return MilkCaps;
public boolean hasCoconut() {
return Coconut;
public void setHasMilk(boolean hasMilk) {
this.Milk = hasMilk;
public void setHasPudding(boolean hasPudding) {
this.Pudding = hasPudding;
public void setHasMilkCaps(boolean hasMilkCaps) {
this.MilkCaps = hasMilkCaps;
public void setHasCoconut(boolean hasCoconut) {
this.Coconut = hasCoconut;
//other set options...
//coffee with milk-cup
public class Coffee extends Drinks {
@Override
super.setDescription(description);
return super.cost()+3;
//test main
public class Main {
public static void main(String[] args) {
Drinks coffee = new Coffee();
coffee.setDescription("coffee with milk-cup");
coffee.setHasMilkCaps(true);
System.out.println("商品:"+coffee.getDescription() + " 价格:"+coffee.cost());
//运行结果
商品:coffee with milk-cup 价格:4.0
Process finished with exit code 0
但是仔细思考之后呢,又会发现这个模式好像也不是很合理
1- 调料价钱的改变会使我们更改现有代码。 2- 一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法 3- 以后可能会开发出新饮料,对这些饮料而言(例如:茶),某些调料可能并不适合,但是在这个设计方式中,Tea(茶)子类仍将继承那些不适合的方法,例如:hasMilkCaps()(加奶盖)。 4- 万一顾客想要双杯奶盖咖啡,怎么办
1- 调料价钱的改变会使我们更改现有代码。
2- 一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法
3- 以后可能会开发出新饮料,对这些饮料而言(例如:茶),某些调料可能并不适合,但是在这个设计方式中,Tea(茶)子类仍将继承那些不适合的方法,例如:hasMilkCaps()(加奶盖)。
4- 万一顾客想要双杯奶盖咖啡,怎么办
好了,我们已经了解利用继承无法完全解决问题,在蜜雪**遇到的问题有:
类数量爆炸、设计死板,以及基类加入的新功能并不适用于所有的子类。
所以,在这里要采用不一样的做法:
我们要以饮料为主体,然后在运行时以配料进行装饰饮料。比方说,如果顾客想要奶盖巧克力咖啡时,那么,要做的是:
装饰
但是关于如何装饰一个对象呢?而委托又该如何实现? 继续往下看
委托
我们以奶盖巧克力咖啡为例子一步一步的进行
MilkCup对象是一个装饰者,它的类型“反映”了它所装饰的对象(本例中,就是指的就是Coffee). 所谓的“反映"指的就是类型一致。 所以MilkCup也有一个cost()方法。通过多态也可以把MilkCup所包裹的任何Drinks当成是 Drinks(因为MilkCup是Drinks的子类)
MilkCup对象是一个装饰者,它的类型“反映”了它所装饰的对象(本例中,就是指的就是Coffee).
所谓的“反映"指的就是类型一致。
所以MilkCup也有一个cost()方法。通过多态也可以把MilkCup所包裹的任何Drinks当成是
Drinks(因为MilkCup是Drinks的子类)
Chocolate是一个装饰者,所以它也反映了Coffee类型,并包括一个cost()方法。
所以,被MilkCup和Chocolate包起来的Coffee对象仍然是一个Drinks,仍然可以具有Coffee的一切行为包括调用它的cost()方法
好了,这是目前所知道的一切
现在,就来看看装饰者模式的定义,并写一些代码,了解它到底是怎么工作的。
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
尝试让我们的蜜雪**也符合上述的设计模式
可以将Drink类抽象为抽象组件(Component),两个(先演示两个,多的也很类似)具体组件Tea、Coffee为具体组件(ConcreteComponent)表示两种饮品,然后我们初始化一个配料的抽象类IngredientDecorator作为装饰器,再将奶盖,巧克力作为具体的配料装饰器.
那么我们将上述的设计转化为代码
public abstract class Drinks { public String description; public abstract float cost(); public String getDescription() { return description; } //other set options...}
public abstract class Drinks {
public abstract float cost();
//咖啡饮品public class Coffee extends Drinks { public Coffee() { description = "coffee"; } @Override public float cost() { return 5; }}
//咖啡饮品
public Coffee() {
description = "coffee";
return 5;
//配料装饰器public abstract class IngredientDecorator extends Drinks { public abstract String getDescription();}//具体配料装饰器Chocolatepublic class Chocolate extends IngredientDecorator { Drinks drinks; public Chocolate(Drinks drinks) { this.drinks = drinks; } @Override public float cost() { return 2 + drinks.cost(); } @Override public String getDescription() { return drinks.getDescription() + " with Chocolate"; }}//具体配料装饰器MilkCuppublic class MilkCup extends IngredientDecorator { Drinks drinks; public MilkCup(Drinks drinks) { this.drinks = drinks; } @Override public float cost() { return 1 + drinks.cost(); } @Override public String getDescription() { return drinks.getDescription() + " with milkcup"; }}
//配料装饰器
public abstract class IngredientDecorator extends Drinks {
public abstract String getDescription();
//具体配料装饰器Chocolate
public class Chocolate extends IngredientDecorator {
Drinks drinks;
public Chocolate(Drinks drinks) {
this.drinks = drinks;
return 2 + drinks.cost();
return drinks.getDescription() + " with Chocolate";
//具体配料装饰器MilkCup
public class MilkCup extends IngredientDecorator {
public MilkCup(Drinks drinks) {
return 1 + drinks.cost();
return drinks.getDescription() + " with milkcup";
我们创建测试类 ,实现一杯奶盖巧克力咖啡
public class Main { public static void main(String[] args) { Drinks coffee2 = new Coffee(); coffee2 = new MilkCup(coffee2); coffee2 = new Chocolate(coffee2); System.out.println(coffee2.getDescription() + ":" + coffee2.cost()); }}//运行结果coffee with milkcup with Chocolate:8.0Process finished with exit code
Drinks coffee2 = new Coffee();
coffee2 = new MilkCup(coffee2);
coffee2 = new Chocolate(coffee2);
System.out.println(coffee2.getDescription() + ":" + coffee2.cost());
coffee with milkcup with Chocolate:8.0
Process finished with exit code
拓展点:
? java源码中的装饰者模式: Java I/O
Java装饰器模式的优点主要包括:
然而,装饰器模式也存在一些缺点:
代码相关代码可以参考 代码仓库??
ps:本文原创,转载请注明出处
原文链接:https://www.cnblogs.com/JerryLau-213/p/18007511
本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728