首页 >> 大全

设计模式:装饰者模式

2023-11-19 大全 31 作者:考证青年

缘由 没什么特别的,之前看懂了,这次自己再复述一下。毕竟把别人讲懂了才是真的懂了。主要参考了head first 设计模式。

书中例子 面和具体的面 例子讲述的是在为星巴克咖啡的制作订单的情况,比如客人点了饮料,那么系统会自动算出价格(不知道是我没有体会到,还是这个例子不太合适,算出价格那么简单的事还需要用到类?,不过不影响我们思考装饰者模式)。不过似乎星巴克离普通的中国人还是太遥远了,我倒可以认为我们想象成中国面馆比较好。

这家中国面馆卖很多种类的面,有我喜欢的哨子面、牛肉面、杂酱面、板面等等面,每一个面都有价格,这是非常正常的。如果每一种面都有一个价格,那么这个订单生成系统好像还比较简单。因为继承是一种不错的选择。下图直接截取了head first 设计模式,所以里面是饮料。那么饮料就相当于我上面所述的面,而牛肉面就相当于一个饮料的一种,比如:Dark Roast。

设计模式装饰者模式__模式设计是什么

加了配料的面 问题来了,面还可以加各类配料,比如你说老板多加一个鸡蛋,另一个说多加一个肉丸,多加一个火腿肠。难道我们为每一种加了配料的面都来实现一种类来计算价钱吗?如此一来,将会有非常多的类。比如加了鸡蛋的牛肉面、加了肉丸的牛肉面.....那么我们的类就继承就会成为下面这个样子。

设计模式装饰者模式_模式设计是什么_

可以看出我们要实现每一个子类就非常辛苦了,需要自己懂把加了丸子、鸡蛋的牛肉面,提前加一遍算好放在这个子类里使用。更可怕的是:如果丸子价格涨了,怎么办?我们又要把所有的有丸子的子类都加一遍吗?

调料试着实例变量 这是一种可以解决的方案。在父类面里面有丸子、鸡蛋的布尔值,和具体价格,那么用户在选择添加了鸡蛋的时候,就将鸡蛋的布尔值改为true,然后再将父类的cost()方法实现为加上所有的配料的价格。那么子类在cost()方法里面用自己这道面的价格加上父类的cost(),就是配料的价格,那么就算出了总共需要多少钱了。

模式设计是什么_设计模式装饰者模式_

设计模式装饰者模式_模式设计是什么_

下图是伪代码,我们可以看出,子类的cost()方面里面调用了父类的cost()方法,而父类cost()方面,主要是判断这个订单有没有加这个某种配料,加了的话就加上这个配料的价格。

_模式设计是什么_设计模式装饰者模式

然而,这样做有以下三种情况会使我们很难处理:

模式设计是什么__设计模式装饰者模式

如果出现新调料,我们需要改变超类。似乎这样很不好某些饮料里面就不能加某些调料,然而我们并没有限制如果某个客户想要双倍的调料,则无法处理。 这里书中: 提出了类应该对扩展开放,对修改关闭。

因为

引入装饰者模式 此时书中引入装饰者模式,其实我是知道看来了代码之后才知道到底是怎么回事。我的理解就是,所谓装饰者,其也是继承于基类(面)的一个实现类,这个实现类必须有有有一个成员变量:就是另一个实现类,也就是被包含的实现类,也就是我们装饰者所要装饰的对象。比如牛肉面就是一个实现类,他是被装饰的,可以被加鸡蛋这个实现类来修饰,加鸡蛋这个实现类的成员变量可以引用牛肉面,那么就组成了加鸡蛋的牛肉面,如果其成员变量引用了哨子面,那么就成了加鸡蛋的哨子面。而且,这个加鸡蛋的哨子面还可以被加丸子的实现类来装饰,那么就是成了加丸子 加鸡蛋的牛肉面。当然,也可以加两个鸡蛋。

所以,我们要把实现类分为两类,一种实现类时调料,其有一个成员变量就是基类的一个对象。另一个实现类就是面的种类:牛肉面、哨子面。

我在书上的图,作了一些额外的说明。如下:

_设计模式装饰者模式_模式设计是什么

另外书上也给了饮料的图,更为简单和清晰些:

设计模式装饰者模式__模式设计是什么

代码

实际上我还是觉得代码描述的更为清楚:

_设计模式装饰者模式_模式设计是什么

public class TestMain {public static void main(String[] args) {//普通牛肉面Noodle beefNoodle = new BeefNoodle();System.out.println(beefNoodle.getDescription() + ":" + beefNoodle.cost());//普通猪肉面Noodle porkNoodle = new PorkNoodle();System.out.println(porkNoodle.getDescription() + ":" + porkNoodle.cost());//加了鸡蛋的牛肉面Noodle beefNoodle2 = new BeefNoodle();beefNoodle2 = new EggCondiment(beefNoodle2);System.out.println(beefNoodle2.getDescription() + ":" + beefNoodle2.cost());//加了鸡蛋和丸子的猪肉面Noodle porkNoodle2 = new PorkNoodle();porkNoodle2 = new EggCondiment(porkNoodle2);porkNoodle2 = new MeatballCondiment(porkNoodle2);System.out.println(porkNoodle2.getDescription() + ":" + porkNoodle2.cost());}
}

/*** 这是一个面的基类。所以面的种类的实现类和调料的装饰类都必须继承这个类。* @author zy**/
public abstract class Noodle {String description = "unknown noodle";public String getDescription(){return description;}public abstract double cost();}

模式设计是什么__设计模式装饰者模式

public class BeefNoodle extends Noodle {public BeefNoodle() {// TODO Auto-generated constructor stubdescription = "牛肉面";}@Overridepublic double cost() {return 10;//表示这个碗牛肉面10元,当然可以做的更专业一些,用个字段来设置。}}

public class PorkNoodle extends Noodle {public PorkNoodle() {// TODO Auto-generated constructor stubdescription = "猪肉面";}@Overridepublic double cost() {// TODO Auto-generated method stubreturn 7;}}

public abstract class CondimenDecorator extends Noodle {/*** 用于装饰的实现类必须有一个成员变量就是要装饰的对象。在这里就是面* 使用Noodle这个基类的原因除了一般的表示种类的面* 用于装饰的实现类,还可以再次被装饰* 有点像加鸡蛋、加丸子的牛肉面* 被装饰了两次* * 此外,书上讲这个成员变量写在了每一个实现类里面,难道不能写在这个父类里面么?* 试试看。*/Noodle noodle;/*** 所以调料必须实现这个方法,这样才能知道这个面的具体描述* 比如 加鸡蛋的牛肉面*/public abstract String getDescription();
}

public class EggCondiment extends CondimenDecorator {public EggCondiment(Noodle noodle) {// TODO Auto-generated constructor stubthis.noodle = noodle;}@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn noodle.getDescription() + "加鸡蛋";}@Overridepublic double cost() {// TODO Auto-generated method stubreturn noodle.cost() + 1;}}

public class MeatballCondiment extends CondimenDecorator {public MeatballCondiment(Noodle noodle) {// TODO Auto-generated constructor stubthis.noodle = noodle;}@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn noodle.getDescription() + "加肉丸";}@Overridepublic double cost() {// TODO Auto-generated method stubreturn noodle.cost() + 2;}}

运行结果

牛肉面:10.0
猪肉面:7.0
牛肉面加鸡蛋:11.0
猪肉面加鸡蛋加肉丸:10.0

java的IO类实现了装饰者模式 如下图所示:

设计模式装饰者模式__模式设计是什么

其中我们可以看出专门作为装饰者。其实现类m就可以得到流中的行数。

书中还举出了简单的例子,自己写了一个的实现类。也就是装饰类。有新兴趣的看看书吧

总结 比较有趣,不过这些设计模式都需要深刻的体会。懂了其含义只是刚刚开始吧。对了,定义很难理解。所以,一直没说。

设计模式装饰者模式__模式设计是什么

源代码 没有上传网盘。代码比较简单。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了