设计模式(7)之装饰模式
2016-04-20 16:40
246 查看
什么是装饰模式
装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
装饰模式的结构
装饰模式的角色和职责
抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口。
具体组件角色:为抽象组件的实现类。
抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。
以一个例子来解释一下,如果我们现在要想造一辆车,对 ! 就是车, Car。
大家都知道,不同的车功能不同,有的车可以跑,废话!有的车可以飞,有的车可以游泳,有的车可以跳跃。。。别激动,我就举个例子。
按照传统的面向对象的思想,我们肯定先定义一个Car的父类,在这个父类中定义一些所有车都具有的功能,比如run(),然后再派生出各种子类继承这个Car父类,然后在子类中再实现自己独特的功能。例如,我声明一个FlyCar继承自Car,然后在FlyCar中实现父类的run(),在实现自己独特的fly()方法。你是不是这么想的,别不承认,一般人都是酱紫想的。我也是这么想的,起初我还很自豪,因为我用到了面向对象的思想!!!
但是,如果现在我想造一个既能游泳又能飞的车怎么办?难道我定义一个FlySwimCar继承自Car,OK,当然可以。但是,随着科技的发展,车的功能越来越丰富,你难道要不停的定义各种组合功能的车吗,你应该知道排列组合吧~~~这显然不符合程序员偷懒的个性。
所以,就有了 装饰模式。我们边看代码,边解释。
首先,定义一个Car基类,当然,这个必须是接口,你懂的,你不可能直接new 一个Car出来吧,谁知道这个Car是具有哪个功能的Car。但是这个接口Car中应该包含最基本的车的功能。
最普通的车不过于实现这个接口了,这个车除了能跑之外,啥都不能干。对,这就是传说中的 【跑车】。
然后,我想造一辆能Fly的车,怎么办?
我们先定义一个抽象类CarDecorator,这个类干嘛的呢?就是对车进行包装,为啥是抽象的呢?因为你造一个能Fly的车和造一个能Swim的车,用的材料啥的肯定都不同吧,也就是说包装的内容都不同吧,所以,这个CarDecorator中定义的是包装类共有操作。就好比,把一辆普通的车改造之前,不论你是改装成能Fly的车还是能Swim的车,你首先是不是获得这个普通的车,获得普通车这个操作就是在CarDecorator基类中定义的。
好了,现在我们就可以造能飞的车了。
同理,我们可以造一个能Swim的车子。
酱紫的话,主函数就会变得很清爽。
运行结果:
呵呵呵,是不是很清爽。但是你有木有发现一个问题,你说造一个能Fly能Swim的车,现在却只造了一个能run和Siwm,能run和Fly的车,还要不要脸了。。。
各位看官,别激动!!!马上造。马上造。
正常人的思维是不是酱紫的,我有一个car,只能run,跑车嘛!!!现在改造(装饰)一下,能游泳了,然后我希望既能游泳也能飞,怎么办?废话,当然是把能游泳的车加一个翅膀啥的。是不是?嗯,这次你想对了。我也是怎么想的。
现在我们改我们的main函数:
改了三处,和原来的main函数比较下,看见没有。为什么这么改,你们不都是怎么想的吗???忘了?往上看看。
为了适应main函数这么改,我们修改其他的文件呢。我们看一下:
原来FlyCarDecorator的构造方法中传递的是Car,你现在传递的是swimCar,swimCar在没改之前是啥类型来着,对,是SwimCarDecorator类型。辣么,你现在知道怎么改了吧。
我们让CarDecorator实现Car接口不就完了吗?
然后分别在FlyDecorator中实现Car中没有实现的run方法
好了,代码应该不报错了吧。。。
现在看下运行结果:
怎么样,我没食言吧,说给你造个能fly能swim的就给你造了。关键代码写得还是辣么的优雅!!!嘿嘿嘿,代码不是我写的,我只是分析下。
但是,有人可能会问,你说改这就改这,说改那就改那,到底改的合不合理呢?唉,你别说,这么一改,比之前还真的合理。
首先,是main方法中的调用逻辑,之前已经说过了,这肯定是符合大多人的思考习惯的。
然后,我们看下CarDecorator实现Car接口合不合理,我们看他的子类FlyDecorator,他继承自CarDecorator,CarDecorator实现了Car接口,所以,FlyDecorator要实现Car中的接口,Car中有两个方法一个是show()和run(),show()方法在CarDecorator中已经定义为抽象方法了,已经被FlyDecorator实现了,现在就剩下run()方法没有实现了,所以,FlyDecorator要实现run()方法,你想想,FlyDecorator实现run方法合理吗???我觉得非常合理,你给车装个翅膀让他飞,他就不能跑了?或许人家跑的更快了呢,或许人家跑的姿势更优雅了呢?所以你也得给FlyDecorator改造车的同时修改原有功能的机会,是不是?所以我觉得很合理。同理,SwimCarsDecorator中的也要实现Car接口中的run()方法。
装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
装饰模式的结构
装饰模式的角色和职责
抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口。
具体组件角色:为抽象组件的实现类。
抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。
以一个例子来解释一下,如果我们现在要想造一辆车,对 ! 就是车, Car。
大家都知道,不同的车功能不同,有的车可以跑,废话!有的车可以飞,有的车可以游泳,有的车可以跳跃。。。别激动,我就举个例子。
按照传统的面向对象的思想,我们肯定先定义一个Car的父类,在这个父类中定义一些所有车都具有的功能,比如run(),然后再派生出各种子类继承这个Car父类,然后在子类中再实现自己独特的功能。例如,我声明一个FlyCar继承自Car,然后在FlyCar中实现父类的run(),在实现自己独特的fly()方法。你是不是这么想的,别不承认,一般人都是酱紫想的。我也是这么想的,起初我还很自豪,因为我用到了面向对象的思想!!!
但是,如果现在我想造一个既能游泳又能飞的车怎么办?难道我定义一个FlySwimCar继承自Car,OK,当然可以。但是,随着科技的发展,车的功能越来越丰富,你难道要不停的定义各种组合功能的车吗,你应该知道排列组合吧~~~这显然不符合程序员偷懒的个性。
所以,就有了 装饰模式。我们边看代码,边解释。
首先,定义一个Car基类,当然,这个必须是接口,你懂的,你不可能直接new 一个Car出来吧,谁知道这个Car是具有哪个功能的Car。但是这个接口Car中应该包含最基本的车的功能。
//Car.java public interface Car { public void run(); // 显示车的功能 public void show(); }
最普通的车不过于实现这个接口了,这个车除了能跑之外,啥都不能干。对,这就是传说中的 【跑车】。
//RunCar.java public class RunCar implements Car{ @Override public void run() { System.out.println("run..."); } @Override public void show() { this.run(); } }
然后,我想造一辆能Fly的车,怎么办?
我们先定义一个抽象类CarDecorator,这个类干嘛的呢?就是对车进行包装,为啥是抽象的呢?因为你造一个能Fly的车和造一个能Swim的车,用的材料啥的肯定都不同吧,也就是说包装的内容都不同吧,所以,这个CarDecorator中定义的是包装类共有操作。就好比,把一辆普通的车改造之前,不论你是改装成能Fly的车还是能Swim的车,你首先是不是获得这个普通的车,获得普通车这个操作就是在CarDecorator基类中定义的。
//CarDecorator.java public abstract class CarDecorator { private Car car; public CarDecorator(Car car) { this.car = car; } //提供方法获取包装之前的Car //为什么要获取包装之前的Car,废话,不获得之前的Car,你怎么添加新的功能? //那么添加功能的方法在哪?我怎么没瞅见,别急呀,往下看,肯定是特定的装饰者添加特定的功能呀。 public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } //为了显示车具有的功能,定以了这个show()方法 public abstract void show(); }
好了,现在我们就可以造能飞的车了。
//FlyCarDecorator.java public class FlyCarDecorator extends CarDecorator { public FlyCarDecorator(Car car) { super(car); } @Override //显示车的功能 public void show() { //先显示原始车的功能,这下知道为啥在CarDecorator中获得改造之前的车了吧。 this.getCar().show(); this.fly();//添加新的功能 } public void fly(){ System.out.println("fly..."); } }
同理,我们可以造一个能Swim的车子。
//SwimCarDecorator.java public class SwimCarDecorator extends CarDecorator{ public SwimCarDecorator(Car car) { super(car); } @Override public void show() { this.getCar().show(); this.swim(); } public void swim(){ System.out.println("swim..."); } }
酱紫的话,主函数就会变得很清爽。
//MainClass.java public class MainClass { public static void main(String[] args) { Car car = new RunCar(); car.show(); System.out.println("--------------------"); SwimCarDecorator swimCar = new SwimCarDecorator(car); swimCar.show(); System.out.println("--------------------"); FlyCarDecorator flyCar = new FlyCarDecorator(car); flyCar.show(); System.out.println("--------------------"); } }
运行结果:
run... -------------------- run... swim... -------------------- run... fly... --------------------
呵呵呵,是不是很清爽。但是你有木有发现一个问题,你说造一个能Fly能Swim的车,现在却只造了一个能run和Siwm,能run和Fly的车,还要不要脸了。。。
各位看官,别激动!!!马上造。马上造。
正常人的思维是不是酱紫的,我有一个car,只能run,跑车嘛!!!现在改造(装饰)一下,能游泳了,然后我希望既能游泳也能飞,怎么办?废话,当然是把能游泳的车加一个翅膀啥的。是不是?嗯,这次你想对了。我也是怎么想的。
现在我们改我们的main函数:
//MainClass.java public class MainClass { public static void main(String[] args) { Car car = new RunCar(); car.show(); System.out.println("--------------------"); //1 Car swimCar = new SwimCarDecorator(car); swimCar.show(); System.out.println("--------------------"); //2 3 Car flyCar = new FlyCarDecorator(swimCar); flyCar.show(); System.out.println("--------------------"); } }
改了三处,和原来的main函数比较下,看见没有。为什么这么改,你们不都是怎么想的吗???忘了?往上看看。
为了适应main函数这么改,我们修改其他的文件呢。我们看一下:
Car flyCar = new FlyCarDecorator(swimCar);
原来FlyCarDecorator的构造方法中传递的是Car,你现在传递的是swimCar,swimCar在没改之前是啥类型来着,对,是SwimCarDecorator类型。辣么,你现在知道怎么改了吧。
我们让CarDecorator实现Car接口不就完了吗?
然后分别在FlyDecorator中实现Car中没有实现的run方法
好了,代码应该不报错了吧。。。
现在看下运行结果:
怎么样,我没食言吧,说给你造个能fly能swim的就给你造了。关键代码写得还是辣么的优雅!!!嘿嘿嘿,代码不是我写的,我只是分析下。
但是,有人可能会问,你说改这就改这,说改那就改那,到底改的合不合理呢?唉,你别说,这么一改,比之前还真的合理。
首先,是main方法中的调用逻辑,之前已经说过了,这肯定是符合大多人的思考习惯的。
然后,我们看下CarDecorator实现Car接口合不合理,我们看他的子类FlyDecorator,他继承自CarDecorator,CarDecorator实现了Car接口,所以,FlyDecorator要实现Car中的接口,Car中有两个方法一个是show()和run(),show()方法在CarDecorator中已经定义为抽象方法了,已经被FlyDecorator实现了,现在就剩下run()方法没有实现了,所以,FlyDecorator要实现run()方法,你想想,FlyDecorator实现run方法合理吗???我觉得非常合理,你给车装个翅膀让他飞,他就不能跑了?或许人家跑的更快了呢,或许人家跑的姿势更优雅了呢?所以你也得给FlyDecorator改造车的同时修改原有功能的机会,是不是?所以我觉得很合理。同理,SwimCarsDecorator中的也要实现Car接口中的run()方法。
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解
- 实例解析C#设计模式编程中简单工厂模式的使用
- 详解C#设计模式编程中生成器模式的使用
- 深入解析C#设计模式编程中对建造者模式的运用