Java中设计模式之装饰者模式-3
装饰者模式:
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。
装饰者核心:实现功能组合
继承与组合区别:
继承
继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。
组合
组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。
与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。
装饰者模式优点
一句话:在原有的基础上 ,增加功能 ,提高效率
1、装饰者模式可以提供比继承更多的灵活性
2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
装饰者模式缺点
一句话:繁琐
1、会产生很多的小对象,增加了系统的复杂性
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
装饰者应用场景
1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
个人理解:
装饰者模式是指在继承父类后,重写父类方法时,不改变父类中该方法的原有功能,只是在该功能基础上添加自己想要扩充的功能。
一句话:父类原有功能不变,子类再添加其他功能
简单实例:
父类
package 设计模式之装饰者模式;
public class Father {
public void run(){
System.out.println("跑步...");
}
}
子类:
在子类中重写run方法时,不改变父类的原有功能,并根据需要添加自己的功能。这里的装饰并不复杂,不存在多层装饰,所以在子类中创建一个父类属性是多余的,但在多层装饰中,这是必要的。
package 设计模式之装饰者模式;
public class Son extends Father {
Father father;
public Son(Father father) {
super();
this.father = father;
}
@Override
public void run() {
System.out.println("欣赏周围的美景...");
father.run();
System.out.println("听歌...");
}
}
测试类:
package 设计模式之装饰者模式;
public class Test {
public static void main(String[] args){
Father father=new Father();
father.run();
System.out.println("son:");
Son son = new Son(father);
son.run();
}
}
结果:
多层装饰实例
借鉴实例,来自http://www.cnblogs.com/xinye/p/3910149.html
逻辑分析图:
1.装饰者基类(被操作的对象)
package com.xinye.test.decoration;
/**
* 食物基类
* @author xinye
*
*/
public abstract class Food {
protected String desc;
public abstract String getDesc();
}
2.被操作对象具体类
鸡肉
package com.xinye.test.decoration;
/**
* 鸡肉
* @author xinye
*
*/
public class Chicken extends Food {
public Chicken(){
desc = "鸡肉";
}
@Override
public String getDesc() {
return desc;
}
}
鸭肉
package com.xinye.test.decoration;
/**
* 鸭肉
* @author xinye
*
*/
public class Duck extends Food {
public Duck(){
desc = "鸭肉";
}
@Override
public String getDesc() {
return desc;
}
}
3.装饰者基类(操作类,对对象实现什么操作)
package com.xinye.test.decoration;
/**
*
* @author xinye
*
*/
public abstract class FoodDecoration extends Food {
@Override
public abstract String getDesc();
}
4.具体操作类
蒸-装饰者
package com.xinye.test.decoration;
/**
* 蒸食物
* @author xinye
*
*/
public class SteamedFood extends FoodDecoration {
private Food food;
public SteamedFood(Food f){
this.food = f;
}
@Override
public String getDesc() {
return getDecoration() + food.getDesc();
}
private String getDecoration(){
return "蒸";
}
}
烤-装饰者
package com.xinye.test.decoration;
/**
* 烤食物
* @author xinye
*
*/
public class RoastFood extends FoodDecoration {
private Food food;
public RoastFood(Food f){
this.food = f;
}
@Override
public String getDesc() {
return getDecoration() + food.getDesc();
}
private String getDecoration(){
return "烤";
}
}
5.测试类(客户端)
package com.xinye.test.decoration;
/**
* 客户端
* @author xinye
*
*/
public class Client {
public static void main(String[] args) {
// 测试单纯的食物
Food f1 = new Chicken();
System.out.println(f1.getDesc());
System.out.println("----------------------");
// 测试单重修饰的食物
RoastFood rf = new RoastFood(f1);
System.out.println(rf.getDesc());
System.out.println("----------------------");
// 测试多重修饰的食物
SteamedFood sf = new SteamedFood(rf);
System.out.println(sf.getDesc());
}
}
执行结果:
鸡肉
烤鸡肉
蒸烤鸡肉
最新文章
- JS /JQuery 获取变量为数字时 容易出错 可能不是数字类型
- UVa 10387- Billiard
- HDU 1027 Ignatius and the Princess II(康托逆展开)
- Windows 之 win10快捷键
- bzoj 1132 POI2008 Tro
- ubunutu_install_sublime_china
- ios App优化
- 保护模式下GDTR,LDTR,全局描述符表,局部描述符表和选择器的关系
- Openfire3.8.2在eclipse中Debug方式启动最简单的方式
- 静态常量(static final)在class文件里是如何的呢?
- git使用方法1
- haproxy反向代理配置示例
- 集大1513 &; 1514班 软件工程第一次作业评分与点评
- Parameter 'ids' not found. Available parameters are [array]
- VUE 浏览器关闭时清空localStorage
- 修改QGIS来支持DPI为96的WMTS/WMS服务
- windows 环境下安装elasticsearch ,ik,head,marvel
- nyoj 吃土豆
- iperf——网络性能测试工具
- 2017年7月ROS学习资料小结