0.写在前面的话
设计模式看了不少,看了又忘,忘了又看,死循环,记笔记才是王道,UML图自己画,示例代码在记事本里敲的,有错误还望指正。看了不少设计模式的文章,不少文字性的大道理,高深莫测的语言让人望而生畏。我打算尽量找一些简单易懂贴近生活,符合设计模式的例子,直接show code。其实最重要的是把模式运用到自己的工程中,代码敲得多、敲得快并没什么,敲得可维护、灵活性高、可扩展、可复用,才是真正的厉害。So,细细琢磨这一点点代码,领略模式的便利之处吧。
1.定义
装饰模式:动态地给一个对象添加一些新功能。
2.UML图
这么抽象的UML图,我真看不懂……
以Car为例的UML图如下:
Car具备基本的移动功能,现在它想新增fly和move两个功能,并且这两个新功能可以任意组合,随时增加随时撤走,原本的移动功能保持不变。那么就可以使用装饰模式对原有的功能进行封装,变换组合。
3.Code
ICar.java
public interface ICar{
void move();
}
Car.java
public class Car implements ICar{
public void move(){
System.out.println("I can run");
}
}
SuperCar.java
//敲重点:装饰器父类要跟具体对象一样实现ICar接口
public SuperCar implements ICar{
protected ICar iCar;
//敲重点:可以通过构造方法,也可以通过一个其他方法,让抽象装饰器持有ICar对象
public SuperCar(ICar iCar){
this.iCar = iCar;
}
public void move(){
if(iCar != null){
iCar.move();
}
}
}
FlyCar.java
public FlyCar extends SuperCar{
public FlyCar(ICar iCar){
super(iCar);
}
public void fly(){
System.out.println("I can fly");
}
public void move(){
//敲重点:super.move通过父类调用ICar的基本功能
super.move();
fly();
}
}
SwimCar.java
public SwimCar extends SuperCar{
public SwimCar(ICar iCar){
super(iCar);
}
public void swim(){
System.out.println("I can swim");
}
public void move(){
super.move();
swim();
}
}
Client.java
public class Client{
public static void main(String[] args){
System.out.println("---Car can:");
Car car = new Car();
car.move();
System.out.println("---add fly:");
FlyCar flyCar = new FlyCar(car);
flyCar.move();
System.out.println("---add swim:");
SwimCar swimCar = new SwimCar(car);
swimCar.move();
System.out.println("---add fly and swim:");
SwimCar swimCar = new SwimCar(new FlyCar(car));
swimCar.move();
}
}
输出
---Car can:
I can run
---add fly:
I can run
I can fly
---add swim:
I can run
I can swim
---add fly and swim:
I can run
I can fly
I can swim
起主要作用的是装饰器父类(SuperCar),装饰器父类中持有具体对象的引用(Car),因此具体装饰器(FlyCar/SwimCar)可以通过父类调用具体对象的基本功能,同时添加上自己特有的功能。
疑问:装饰器父类(SuperCar)与具体对象(Car)为何要继承同一接口(ICar)? 如果SuperCar不继承ICar接口,而只是通过聚合方式持有ICar类型对象引用,同样能够调用ICar对象的功能啊?
自问自答:因为这样一来具体装饰器类(FlyCar)和具体对象类(Car)都能作为ICar的实现类传入装饰器父类(SuperCar)中,进行功能组合封装时就能无差别的使用具体装饰类和具体对象类。
(通过SuperCar继承ICar接口,这样一来具体抽象器(FlyCar)跟具体对象 (Car)继承自同一接口,FlyCar可以替代Car,或者说FlyCar的性质其实跟Car是一样的,两者处于同样的层次,只不过FlyCar不仅具备Car的基本功能move,而且还有自己独特的功能fly。)
优点: ①如果想使用具备fly功能的车就使用FlyCar,只想使用move功能的车就使用Car,FlyCar的存在并不影响之前的工程,FlyCar作为一个装饰品随时可以撤走,同时Car想要增加新功能时可以随时再新增一个XXCar类。将具体对象与对象新增的功能解耦。
②具体对象和具体装饰器都继承自同一个接口,两者可以方便的通过接口类统一代表,所以可以方便的一层又一层的包裹具体对象或者具体装饰器进行功能的组合。