一、定义
装饰(decorate)模式又称为包装(Wrapper)模式,顾名思义,装饰模式就是对XXX进行包装,使其功能,职责更加完善;说白了就是给对象增加新的功能,是继承关系的一个替代方案。
二、为什么要使用Decorator模式?
我们通常来使用继承来实现功能的扩展,如果这些需要扩展的功能很繁多,那么势必会增加系统的复杂性,使程序显得十分的“臃肿”,耦合度很高,同时,使用继承实现功能的扩展,我们必须可预见这些扩展功能,这些功能是编译时就确定的,是静态的。
思想:为一个对象已有的子类添加一些额外的职责。
三、继承方式实现功能的扩展
1、简单案例
代码实例:
抽象接口
public interface AbstractCar {
public abstract void move();
}
基础实现
public class CarImpl implements AbstractCar{
@Override
public void move() {
System.out.println("car is driving on the highway");
}
}
功能扩展(飞行)
public class FlyCar extends CarImpl {
public void fly(){
System.out.println("car is driving in the air");
}
@Override
public void move() {
super.move();
fly();
}
}
功能扩展(水行)
public class FlyAndSwimCar extends FlyCar {
public void swim(){
System.out.println("car is driving in the water");
}
@Override
public void move() {
super.move();
swim();
}
}
测试类
public class Tester {
public static void main(String[] args) {
AbstractCar car1 = new CarImpl();
car1.move();
System.out.println("------add fly function-----");
AbstractCar car2 = new FlyCar();
car2.move();
System.out.println("------add swiming function-----");
AbstractCar car3 = new FlyAndSwimCar();
car3.move();
}
}
输出
car is driving on the highway
------add fly function-----
car is driving on the highway
car is driving in the air
------add swiming function-----
car is driving on the highway
car is driving in the air
car is driving in the water
四、分析
首先我们先来看下类的继承体系
Car
|--FlyCar
|--FlyAndSwim
|--新增其他功能
|--SwimCar
|--CarImpl
如果我们有更多的需求,这个继承体系会愈来愈大;这时,我们就可以使用装饰者模式。
五、装饰(Decorate)模式
1、简单案例1
代码实例
被装饰者
/**
* 抽象汽车类,被装饰者
* @author Administrator
*
*/
public interface Car {
public abstract void move();
}
装饰者
public abstract class CarDecorator implements Car {
private Car car;
public CarDecorator(Car car) {
this.car = car;
}
@Override
public void move() {
this.car.move();
}
}
被装饰者初始装饰
public class CarImpl implements Car {
/**
* 被装饰者初始状态有些自己的装饰
*/
@Override
public void move() {
System.out.println("car is moving on the highway");
}
}
水行装饰
public class SwimingCar extends CarDecorator {
public SwimingCar(Car car) {
super(car);
}
public void DrivingInWater(){
System.out.println("car is driving in the water");
}
@Override
public void move() {
super.move();
DrivingInWater();
}
}
飞行装饰
public class FlyCar extends CarDecorator {
public FlyCar(Car car) {
super(car);
}
public void DrivingInAir(){
System.out.println("car is driving in the air");
}
@Override
public void move() {
super.move();
DrivingInAir();
}
}
测试类
public static void main(String[] args) {
Car car = new CarImpl();
car.move();
System.out.println("---------------");
CarDecorator fly = new FlyCar(car);
fly.move();
System.out.println("---------------");
CarDecorator swiming = new SwimingCar(car);
swiming.move();
System.out.println("---------------");
CarDecorator flyAndSwim = new FlyCar(swiming);
flyAndSwim.move();
}
}
我们再来看下他的继承体系
Car
|--CarDecorator
|--FlyCar
|--SwimingCar
|--其他装饰
、
、
、
|--CarImpl
由此可知、使用装饰模式他的继承体系不像单纯的使用继承那样庞大。
1、简单案例2
代码实例
被装饰者
/**
* 定义被装饰者
*
* @author Administrator
*
*/
public abstract class Pancake {
protected String name;
public String getName() {
return name;
}
public abstract double getPrice();
}
装饰者
/**
* 定义装饰者
*
* @author Administrator
*
*/
public abstract class PancakeDecorate extends Pancake {
private Pancake pancake;
public PancakeDecorate(Pancake pancake) {
this.pancake = pancake;
}
@Override
public String getName() {
return this.pancake.getName();
}
@Override
public double getPrice() {
return this.pancake.getPrice();
}
}
初始化装饰
public class PancakeInit extends Pancake {
public PancakeInit(){
name = "煎饼";
}
@Override
public double getPrice() {
return 8;
}
}
生菜装饰
public class LettuceDecorate extends PancakeDecorate {
public LettuceDecorate(Pancake pancake) {
super(pancake);
}
@Override
public String getName() {
return super.getName()+" 加生菜";
}
@Override
public double getPrice() {
return super.getPrice()+1;
}
}
鸡蛋装饰
public class EggDecorate extends PancakeDecorate {
public EggDecorate(Pancake pancake) {
super(pancake);
}
@Override
public String getName() {
return super.getName()+"加鸡蛋";
}
@Override
public double getPrice() {
return super.getPrice()+2;
}
}
火腿装饰
public class HamDecorate extends PancakeDecorate {
public HamDecorate(Pancake pancake) {
super(pancake);
}
@Override
public String getName() {
return super.getName()+" 加火腿";
}
@Override
public double getPrice() {
return super.getPrice()+2;
}
}
测试类
public class Tester {
public static void main(String[] args) {
// 基本的煎饼
Pancake pancake = new PancakeInit();
System.out.println(pancake.getName() + " 价格:" + pancake.getPrice());
// 只加生菜
PancakeDecorate pd = new LettuceDecorate(pancake);
System.out.println(pd.getName() + " 价格:" + pd.getPrice());
// 只加火腿
pd = new HamDecorate(pancake);
System.out.println(pd.getName() + " 价格:" + pd.getPrice());
// 加鸡蛋,加火腿
pd = new HamDecorate(new LettuceDecorate(pancake));
System.out.println(pd.getName() + " 价格:" + pd.getPrice());
}
}
输出
煎饼 价格:8.0
煎饼 加生菜 价格:9.0
煎饼 加火腿 价格:10.0
煎饼 加生菜 加火腿 价格:11.0
六、总结
个人理解:装饰者模式的设计对扩展开放、对修改关闭,体现在如果我想扩展被装饰者的职责,无须修改装饰者抽象类,只需要继承装饰者抽象类,实现额外的装饰或者职责只需要对被装饰者进行包装即可。
如果你细心的话上面示例的调用类似于我们读取文件时的调用:
FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr);
实际上Java 的I/O API就是使用装饰模式实现的,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐.