设计模式之二:装饰者模式

来源:互联网 发布:阿里巴巴软件开发 编辑:程序博客网 时间:2024/05/21 01:46

 


设计原则:开放关闭原则

定义:类应该对扩展开放,对修改关闭。

理解: 我们的目标是允许类容易扩展,在不修改现有代码就可以搭配新的行为,这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需要。

在观察者模式中,通过加入新的观察者,我们可以在任何时候扩展subject,而且不需要向主题中添加代码。

注意事项:遵守开放-关闭的原则,通常会引入新的抽象层次,增加代码的复杂度,你需要把注意力集中在设计中最有可能改变的地方,然后应用这个原则。

 

总结体会:

关于少继承多组合的原则的进一步体会:利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类的子类都会继承相同的行为,然而,如果能够利用组合的方法,扩展对象的行为,就可以在运行时动态的进行扩展,同时利用组合可以将在设计超类时还没有想到的新功能加在对象时,这样可以不用修改原来的代码。

解释:

对动态的理解:在运行时动态的根据一个结果,有条件的或者无条件的进行组合

装饰着模式定义:

动态的将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的替换方案。

装饰者模式通常是用其他类似于工厂或生成器模式创建的。这样他们会封装的很好.

进一步理解:java API中经常使用此方法,InputStream

1.装饰者类反映出被装饰者的组件类型,(他们具有相同的类型,都经过接口或者继承实现)

2.装饰者可以在被装饰着的行为前或者后加自己行为,设置不让它运行

3,装饰者一般对组件的客户是透明的,除非客户程序依赖于具体的类型,则这时候可能用          装饰者模式不太合适

4.装饰者会导致设计中出现小对象,如果过度使用,会让程序显的复杂。

 

 

 

每个组件可以单独使用,或者被装饰着包起来使用,每个装饰着都“有一个”组件,也就是说,装饰着有一个实例变量保存着某个component的引用。

进一步理解:目前我们能得到的信息

1.装饰着和被装饰者都具有相同的超类型

2.你可以直接用一个或多个装饰着包装一个对象

3.既然装饰者和被装饰者对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合都可以同装饰过的对象代替他。

4.对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来修饰

5.装饰者可以在所委托被装饰者的行为之前或者之后,加上自己的行为,已达到特定的目的。

 

案例:

咖啡厅在销售咖啡时,需要按照要求在其中加入各种调料,咖啡厅会根据所加入的调料收取不同的尝试。

做法1:每种咖啡单独做成一个类。

问题:这是一个维护的噩梦,价格的每次调整,新增一个口味,代码可维护性太差

做法2:创建一个咖啡的基类Beverage,有布尔值的变量即各种调味品的名称,以及对应的描述这些价格的变量,这些调味料的变量都有hasXX setXXX这样的方法,基类中的cost中方法,计算价格。加入子类 继承基类,同时重写cost方法,在这个方法中,超类cost()将计算所有调料的价格,而子类会扩展超类的功能,把指定的饮料的类型的价钱也加进去。

问题:只需要几个类,就可以解决问题,但是有如下问题:

1.调料价钱的改变会使我们更改现有代码。

2.一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法。

3.以后可能会开发新的饮料,对这些饮料而言,某些调料可能并不适合,但是在这个设计方式中,子类仍然会继承这些不需要的方法。

4.万一顾客想要双倍的某某调味料价钱怎么算。

做法3:我们以饮料为主体,然后在运行时以调料来装饰(decorate)饮料,有一个公共Component类,装饰者和被装饰者(具体的Component类)都继承,装饰者和被装饰者之间的公共方法可以放入基类中,如果基类是抽象类,可以在抽象类中实现一部分的方法,这样的方法,如果子类不需要重写,可以直接使用,当然可以通过子类传递参数进来,使得方法是动态的。 另外如果其他子类如装饰者如果需要完全重写这个方法,可以在装饰者的基类中,把这个方法在设为抽象类,然后单独重写。

因为装饰者的单独的基类继承了Component类,现在具体的装饰者需要继承这个所谓的基类,需要在这个基类中定义一个实例变量,实例变量是与被装饰者的公共基类。然后在具体的装饰者类中的构造方法中传入这个参数,设置实例变量的值。当然也可以在每个子类中自己定义实例变量。

问题:如果代码是依赖于具体的组件类型(如针对某款具体的饮料打折,而不包括调料),那么装饰者就会导致程序出错,只有在针对抽象组件类型编程时,才不会因为装饰者受到影响,如果是前者,那么可能这个模式就不合适了。

 


Q:为什么用到了继承?

A:这么做的重点在于装饰者和被装饰者必须是一样的类型,也就是有共同的超类,这是关键所在,这样就可以用装饰者替换被装饰者。在这里我们利用继承达到的“类型匹配”,而不是用继承获取“行为”。

 

 

 

0 0