java设计模式---装饰者模式

一:装饰者模式

       想要学会装饰者模式必须理解装饰者模式的作用和所依赖的原则。

       理解了作用可以帮助我们在以后的开发中怎么应用装饰者模式,理解了原则可以帮助我们怎么去书写装饰者模式。

二:装饰者模式的作用:

       官方作用说明:动态地将责任附加到装饰者对象上。

       自己的理解:对某一类对象的功能的扩展,就可以使用装饰的模式。

三:装饰者模式依赖的原则:

       1:开放--关闭原则:

            对类的功能扩展开放,对类的源码的修改进行关闭。

       2:开放--关闭原则的详解:

          我们可以对已有的类添加功能,但不能对已有的类进行修改操作(所谓的修改就是增删改),意思别人写好的代码我们不 能对他进行修改。那么问题来了我们不能修改别人的代码,如何扩展类的功能呢?请看下面代码的分析,你就能看懂装饰者模式是如何不改源码就能扩展类的功能。

四:源码分析

        现在我们假设在很久以前有一个程序员写了一个Beverage(饮料)抽象类和继承了Beverage的具体类EspressoCoffe(浓咖啡),用description属性描述饮料,用cost方法计算咖啡的价格代码如下   :

package decrationModel;
/*
 * Beverage是饮料类
 */
public abstract class Beverage {
 /*
  *  description的汉语意思:描述
  *   所以这个属性是用于描述饮料的
  */
          String description="Unknow Beverage!";
 
 /*
  * 这个方法适用于获取饮料的描述属性的。
  */
     public String getDescription() {
            return description;
      }


 /*
  *   这个方法是用来计算饮料价格的,
  *    把这个方法写成抽象的原因是:每种饮料的价格都不一样,所以需要子类实现自己的价格
  */
      public abstract double cost();
}

package decrationModel;
/*
 * EspressoCoffe汉语意思:浓咖啡
 */
public class EspressoCoffe extends Beverage{

 

      public EspressoCoffe() {
            //description这个属性是从父类继承来的,用于描述这个饮料是浓咖啡
            description="EspressoCoffe";
       }


 @Override
     public double cost() {
      //浓咖啡的价格是2.00
       return 2.00;
     }
 
}

现在的需求是:又来了一个程序员他想往EspressoCoffe(浓咖啡)里添加摩卡,现在看看装饰者模式是怎么往浓咖啡里添加摩卡的且不修改源码。

在看装饰者模式之前的先明白两个定义:一个是装饰者,一个是被装饰者。

现在我们是在往浓咖啡(EspressoCoffe)里添加摩卡(Mocha),这就是在用摩卡装饰浓咖啡。

所以浓咖啡(EspressoCoffe)是被装饰者,摩卡(Mocha)是装饰者。

 在摩卡(Mocha)类里声明了一个饮料(beverage)属性,用来接收被装饰者。

package decrationModel;
/*
 * CondimentDecorator的汉语意思:调料装饰器
 *

*所有装饰器都必须继承此类

*
 *  在这里可能大家会迷糊为什么要让装饰器继承饮料类,这么做的原因是什么,
 *  我们稍后再说,继续看看代码。大家也可以暂时忽略这个问题。
 */
public abstract class CondimentDecorator extends Beverage{

 /*
  * 每个调料子类都必须重写这个方法,这个问题大家看子类的实现遍知道原因了。
  */
 public abstract String getDescription();

}

package decrationModel;
/*
 * 这是Mocha(摩卡调料)
 *
 */
public class Mocha extends CondimentDecorator {
 //此对象是被装饰者
 Beverage beverage;
 
 public Mocha(Beverage beverage) {
  this.beverage=beverage;
 }
 
 @Override
 /*
  * 调料类重写父类的方法
  */
 public String getDescription() {
  return beverage.getDescription()+",Mocha";
 }

 @Override
 /*
  * 返回调料与被装饰者的价格
  */
 public double cost() {
  return beverage.cost()+3.00;
 }

}

public static void main(String[] args) {
  //1现在顾客点了一杯浓咖啡
  EspressoCoffe coffe=new EspressoCoffe();
  
  //2:顾客现在又要求在浓咖啡里添加点摩卡
  Mocha mocha=new Mocha(coffe);
  
  //3:现在顾客感觉添加摩卡的咖啡不错,他想看看这杯添加摩卡浓咖啡的介绍
  
  String description = mocha.getDescription();
  System.out.println("介绍:"+description);
  //4顾客喝完咖啡就需要结账了
  
  double cost = mocha.cost();
  System.out.println("费用:"+cost);
 }

现在我们来看看所谓的功能扩展是怎么扩展的:

功能的扩展其实就是将装饰者的功能与被装饰者的功能进行组合。

而我们也对两个功能进行了组合:在装饰者getDescription()与cost()方法。

现在我们又来解释一下官方的定义:动态地将责任附加到装饰者对象上。

如果顾客只要浓咖啡而不要摩卡或者其他调料装饰,那么获取咖啡的描述和价格都需要用咖啡对象去调用。

如果顾客要求用摩卡或者其他调料装饰,那么获取浓咖啡价格和描述我们就不要用浓咖啡对象去调用了,而是交给摩卡对象去调用。这样我们获取到的是总价格和总描述。所以获取价格和描述的责任我们也动态的附加到摩卡装饰者对象上面去了。

最后一个问题:为什要让装饰者与被装饰者具有共同的祖先(例如浓咖啡和摩卡就具有共同的祖先)

这么做的目的是为了继承类型,而不是继承行为。因为摩卡装饰浓咖啡之后他还是一杯饮料。代码里面我们也确实没有继承行为,我们都是重新写了子类的行为。

设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,(记住是生成很多的子类),增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。

 要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为

提示:io流使用的就是装饰者模式

 

你可能感兴趣的:(java设计模式,java装饰者模式)