前言:初学设计模式如果有错误请多多指教(Thanks >-<)
装饰模式的介绍
装饰模式又称为装饰者模式,是结构型模式中的一种,指的允许向一个现有的类添加新的功能,而又不改变其结构。(就好比对一个对象进行装饰添加一些东西但又不改变该对象本身的结构)
装饰模式参与的角色
参与角色 | 功能 |
---|---|
抽象的被装饰类角色 | 作为被装饰类和装饰类之间的接口 |
具体被装饰角色 | 实现了被装饰类 |
抽象的装饰类角色 | 持有一个抽象的被装饰类角色(实现了抽象的被装饰类角色) |
具体的装饰类角色 | 实现了具体装饰,负责给被装饰对象进行装饰(继承了抽象的的装饰类角色) |
装饰模式的UML图
装饰模式案例
接着篇章三的案例,小明现在选择使用保温杯,然后小明决定在网上购买保温杯,小明看到一家卖保温杯的点,里面可以自选保温杯的颜色(可供自选的颜色有蓝色、黑色和蓝黑色),现在我们使用装饰模式来实现这个案例。模块设计:设计抽象的被装饰类角色(杯子抽象类)、设计具体被装饰角色(将杯子类进行实现)、设计抽象的装饰类角色(将杯子的颜色进行抽象)和设计具体的装饰类角色(保温杯可选的颜色)
(1)设计一个抽象的被装饰类角色(Cup类)
/**
*
* @Introduction 该类是抽象的被装饰的角色,是一个抽象类
*
*/
public abstract class Cup {
public abstract void buyCup();
}
(2)设计一个具体的被装饰类角色(RealCup类)
/**
* @Introduction 该类实现了Cup类,是被装饰的具体对象
*/
public class RealCup extends Cup{
/**重写买杯子方法*/
@Override
public void buyCup(){
System.out.println("买杯子");
}
}
(3)设计一个抽象装饰类角色(DecorateCup类)
/**
* @Introduction 该类实现了Cup,以及在内部定义了一个Cup类的引用
*/
public abstract class DecorateCup extends Cup{
protected Cup cup;//该成员变量是被装饰对象的引用
}
(4)设计一个具体装饰类角色(BlueCup类)
/**
* @Introduction 该类是一个具体的装饰类,实现了抽象的装饰角色,在该类在构造时就必须传入被装饰的对象(装饰角色单独存在无意义)
*/
public class BlueCup extends DecorateCup{
/**构造方法,用于在构造该具体类的时候指明被装饰的对象*/
public BlueCup(Cup cupp) {
this.cup=cupp;
}
/**重写了买杯子的方法(这里画上重点——在重写的方法中,调用传入的被装饰对象的buyCup方法然后加上该具体装饰类的特有属性)*/
@Override
public void buyCup() {
this.cup.buyCup();
System.out.println("颜色选择:蓝色");
}
}
(5)设计一个具体装饰类角色(BlackCup类)
/**
* @Introduction 该类是一个具体装饰角色,表明小明买的杯子颜色是黑色,实现了抽象的装饰类角色
*/
public class BlackCup extends DecorateCup{
/**构造方法,用于在该具体装饰类创建的时候就表明具体的被装饰对象*/
public BlackCup(Cup cupp){
this.cup=cupp;
}
/**重写了Cup类中的买杯子方法(同样这里画重点)*/
public void buyCup(){
this.cup.buyCup();
System.out.println("颜色选择:黑色");
}
}
(6)模拟用户界面代码
/**
* @Introduction 该类模拟用户界面
*/
public class Main {
public static void main(String[] args){
RealCup cup=new RealCup();//创建一个具体被装饰的对象实例
//小明买蓝色的杯子
BlueCup blueCupOne=new BlueCup(cup);//使用蓝色来装饰这个被装饰的对象
blueCupOne.buyCup();
//小明买黑色的杯子
BlackCup blackCupOne=new BlackCup(cup);
blackCupOne.buyCup();
//小明买蓝色和黑色的杯子
BlueCup blueCupTwo=new BlueCup(cup);
BlackCup blackCupTwo=new BlackCup(blueCupTwo);
blackCupTwo.buyCup();
}
}
案例解析
首先我们考虑不使用设计模式来实现该功能,面对这样一个功能实现我们可以首先设计一个抽象的杯子类,该类是所有可选颜色杯子类的抽象,然后设计所有的可选杯子的类,并让所有可选杯子类继承杯子的抽象类,在该题中我们需要设计3个具体的杯子类,分别是蓝色杯子类、黑色杯子类和蓝黑色杯子类,然后我们在用户界面在实例化这些具体杯子类来达到用户选择杯子的要求,现在我们来分析一下这种做法的优劣:
优点:开放—封闭原则比较好,该类程序可拓展性比较好(比如要加一个新类型的杯子,直接设计一个相关类继承杯子类即可)
缺点:代码不够灵活,每次我们需要推出一个新的杯子类型都要设计一个新的类;广泛的使用继承,提高了程序的耦合性,如果设计到对抽象杯类的修改,则可能会造成不好影响;代码复用性不高。
下面我们来分析一下使用装饰模式,在装饰模式中我们一共有四种角色,对于被装饰类(包括抽象的和具体的)他们无需知道谁会装饰他们,他们只需要实现自己的功能即可;对于装饰类(包括抽象的和具体的),它们同样无需知道他们装饰的对象是谁(装饰对象的决定在用户界面实现),每一个装饰类只需要完成好自己装饰的功能。装饰模式的优劣分析(重点):
优点:
(1)程序拥有良好的灵活性,由于装饰可以随意搭配和组合,不同的装饰相互搭配会有不同的结果。
(2)可拓展性比较好,就上例来说若商家需要增加粉色的杯子,我们只需要在装饰类中增加一个新类就好。
(3)复用性比较强,如果我们还有一个玻璃杯类上架(前面是保温杯类),我们只需要然玻璃杯类继承抽象杯类,然后就可以在用户界面使用装饰类来装饰玻璃杯。
缺点:
(1)由于程序灵活性的特点,这意味着程序的复杂性会大大增加(如果出现错误,由于各个类之间层层装饰找错误比较麻烦——这就是有得必有失吧)
(2)由于装饰类都在用户界面和界面逻辑一起实现,所以会导致用户界面过于杂乱同时会暴露相关类的信息。(可以考虑使用使用半透明或者透明的装饰类——将装饰过程进行包装封闭)
(3)由于各种装饰类相互装饰,可能会导致代码难以理解,过度使用的话会使程序变得很复杂。