JAVA设计模式(七)——装饰模式

1、装饰模式

        装饰模式又被称为包装模式,通过一种对客户端透明的方式来扩展的功能,是继承关系的一个替换方案。

        上面这句话,主要体现两个意思:一是扩展客户端的功能,二是继承关系的一个转换。等下我们在后面的设计原则和结构示意图中会详细说明一下。


2、设计原则

1)多用组合,少用继承。

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2)类应设计的对扩展开放,对修改关闭。


3、结构视图

3.1 结构视图

      按照我写博客的惯例,这里应该丢出一个示例结构图示,这也是我从网上copy下来的,我只是做个说明就好了,没必要重复画一个一样的图示:


        从结构图示中,我们可以看到,最上层是一个接口,而不是类,我们使用了接口的实现,这就符合我们在第2条中的原则,用接口的实现替代类的实现。


3.2 角色和职责

抽象组件角色:一个抽象接口,是被装饰类和装饰类的父类接口。(Component)

具体组件角色:抽象组件的实现类。(ConcreteComponent)

抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。(Decorator)

具体装饰角色:抽象装饰的实现类,负责具体的装饰实施操作。(ConcreteComponent)


4、基础示例代码

        抽象组件,抽象接口代码示例:

public interface Car {
	
	/**
	 * 展示
	 */
	public void show();
	
	/**
	 * 跑
	 */
	public void run();
}

        具体组件,Car接口的实例类,CarRun,表示会跑的车:

public class CarRun implements Car{

	@Override
	public void show() {
		// TODO Auto-generated method stub
		this.run();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("我可以跑-----");
	}

}

       抽象装饰类,也是一个抽象的类,示例如下:

/**
 * 车的装饰类,本身持有一个对car的引用
 * 
 * @author ljtyzhr
 * 
 */
public abstract class CarDecorator{
	
	private Car car ;
	public CarDecorator(Car car) {
		this.car = car;
	}
	
	public abstract void show();

	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}
}

        具体的装饰类实例对象,这里写一个会“飞”的车,示例如下:

public class FlyCarDecorator extends CarDecorator{

	public FlyCarDecorator(Car car) {
		super(car);
	}

	@Override
	public void show() {
		// TODO Auto-generated method stub
		this.getCar().show();
		this.fly();
	}
	
	public void fly(){
		System.out.println("可以飞^_^");
	}
}

        写完上面的代码之后,我们可以使用一个测试类来看看,如下:

public class MainClass {
	
	public static void main(String[] args) {
		CarRun run = new CarRun();
		CarDecorator flyCarDecorator = new FlyCarDecorator(run);
		flyCarDecorator.show();
	}
}

       这里,通过装饰模式,就可以让会飞的车,既能够普通的跑,也能特殊的飞。


5、扩展代码示例

       单纯的看上面的代码,似乎装饰模式也没有什么特别的地方,如果我们需要写一个会“游泳”的汽车,可以添加一个装饰模式实例类。那么装饰模式与之前我们所提到的继承关系又有什么区别呢?我们完全可以使用类的继承来实现呀。

       但是,如果我们提出,一辆汽车,既能够具备基本的会跑,也有两项高级的技能——“游泳”和“飞”,这个时候怎么办呢?难道我们要单独写一个装饰类,重复写着刚才写下的代码吗?No,装饰模式的优势,就是在此刻得到体现的。

      不过这里需要比上面的代码,有一个不同之处,就是我们的装饰实例对象,也要实现抽象组件这个接口,代码如下:

/**
 * 会游泳的车
 * 
 * @author ljtyzhr
 * 
 */
public class SwimCarDecorator extends CarDecorator {

	public SwimCarDecorator(Car car) {
		super(car);
	}

	@Override
	public void show() {
		// TODO Auto-generated method stub
		this.getCar().show();
		this.swim();
	}

	public void swim() {
		System.out.println("可以游泳~~");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub

	}

}


        测试案例如下,我们需要一个既能够游泳,也能够飞的车,那么代码如下:

public class MainClass {
	
	public static void main(String[] args) {
		CarRun run = new CarRun();
		CarDecorator swimCarDecorator = new SwimCarDecorator(run);
		CarDecorator flySwimCarDecorator = new SwimCarDecorator(flyCarDecorator);
		flySwimCarDecorator.show();
	}
	
}

5、适用性

以下情况使用Decorator模式
1)需要扩展一个类的功能,或给一个类添加附加职责。
2)需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3)需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。


6、装饰总结

        Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。通过使用不同的具体装饰类以及这些装饰类的排列组合,我们可以创造出很多不同行为的组合。
       这种比继承更加灵活机动的特性,装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。


7、Java实例

      读者如果对上面代码仔细研读,联想一下,是否能够想起,在Java中有地方就使用到了这种模式呢?也许大家接触过,一时想不起,实际上,在java的IO流中,就使用了装饰模式。最基本的IO流只能读取文件,封装过的类文件,可以采用多种读取类型。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值