设计模式--装饰器(Decorator)模式
来源:互联网 发布:ff14国际服数据库app 编辑:程序博客网 时间:2024/06/03 00:00
- 意图
- 示例1汉堡的组合
- 结构及角色
- 示例2人的行为的组合
- 何时使用
- java IO
1. 意图
装饰器模式的意图是在运行时组合操作的新变化。
动态地给一个对象添加一些额外的职责。相比生成子类更加灵活。
装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。
装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需要来动态组合的这样一个模式。
2. 示例1:汉堡的组合
下面这个例子有助于理解 装饰的流程和作用
现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。
汉堡基类(被装饰者)
package decorator;public abstract class Humburger { private String name; public String getName(){ return this.name; public abstract double getPrice(); }
鸡腿堡类(被装饰者的初始状态)
package decorator;public class ChickenBurger extends Humburger{ private String name; public ChickenBurger() { this.name="鸡腿堡"; } @Override public double getPrice(){ return 10; } @Override public String getName(){ return this.name; }}
配料的基类(装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料)
package decorator;public abstract class Condiment extends Humburger{ public abstract String getName();}
生菜(装饰者的第一层)
package decorator;public class Lettuce extends Condiment{ private Humburger hum; Lettuce(Humburger hum){ this.hum=hum; } @Override public String getName(){ return hum.getName()+ " 加生菜"; } @Override public double getPrice(){ return hum.getPrice()+1.5; }}
辣椒(装饰者的第二层)
package decorator;public class Chilli extends Condiment{ private Humburger hum; public Chilli(Humburger hum) { this.hum=hum; } @Override public String getName(){ return hum.getName()+" 加辣椒"; } @Override public double getPrice(){ return hum.getPrice(); //辣椒免费 }}
测试
package decorator;public class Test { public static void main(String[] args) { Humburger hum = new Chilli(new Lettuce(new ChickenBurger())); System.out.println(hum.getName()); System.out.println(hum.getPrice()); }}//结果鸡腿堡 加生菜 加辣椒11.5
3. 结构及角色
Component
:组件对象的接口,可以给这些对象动态的添加职责;
ConcreteComponent
:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;
Decorator
:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。
ConcreteDecorator
:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。
4. 示例2:人的行为的组合
组件接口
package decorator;public interface Human { public void wearClothes(); public void walk();}
具体实现接口的对象
package decorator;public class Person implements Human{ @Override public void wearClothes() { System.out.println("穿什么呢"); } @Override public void walk() { System.out.println("去哪里呢"); }}
装饰器接口(抽象类)
package decorator;public abstract class Decorator implements Human{ protected Human human; public Decorator(Human human){ this.human = human; } public void wearClothes(){ human.wearClothes(); } public void walk(){ human.walk(); }}
装饰器的具体实现对象A、B、C…
package decorator;public class Decorator_first extends Decorator{ public Decorator_first(Human human) { super(human); } public void goRoom(){ System.out.println("进房子..."); } public void findMap(){ System.out.println("找地图..."); } @Override public void wearClothes(){ super.wearClothes(); goRoom(); } @Override public void walk(){ super.walk(); findMap(); }}
package decorator;public class Decorator_two extends Decorator{ public Decorator_two(Human human) { super(human); } public void goClothesPress(){ System.out.println("去衣柜找找..."); } public void findPlaceOnMap(){ System.out.println("在Map上找找..."); } @Override public void wearClothes(){ super.wearClothes(); goClothesPress(); } @Override public void walk(){ super.walk(); findPlaceOnMap(); }}
package decorator;public class Decorator_three extends Decorator{ public Decorator_three(Human human) { super(human); } public void findClothes(){ System.out.println("找到一件衣服"); } public void findTarget(){ System.out.println("找到目的地"); } @Override public void wearClothes(){ super.wearClothes(); findClothes(); } @Override public void walk(){ super.walk(); findTarget(); }}
测试
package decorator;public class TestHuman { public static void main(String[] args) { Human human = new Person(); //链式调用 Decorator decorator = new Decorator_three( new Decorator_two(new Decorator_first(human))); decorator.wearClothes(); decorator.walk(); }}//结果穿什么呢进房子...去衣柜找找...找到一件衣服去哪里呢找地图...在Map上找找...找到目的地
5. 何时使用
在以下两种情况下可以考虑使用装饰器模式:
(1)需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责。(2)如果不适合使用子类来进行扩展的时候,可以考虑使用装饰器模式。
6. java I/O
java中的IO是明显的装饰器模式的运用。FilterInputStream
,FilterOutputStream
,FilterRead
,FilterWriter
分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream
,OutputStream
,Reader
,Writer
类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。
继承自InputStream
,OutputStream
,Reader
,Writer
这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream
,FilterOutputStream
,FilterRead
,FilterWriter
这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator
类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream
是InputStream
的一个子类,从文件中读取数据流,BufferedInputStream
是继承自FilterInputStream
的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream
装饰FileInputStream
,就可以提供一个内存缓冲区来保存从文件中读取的输入流。
图解如下:
①组件接口,相当于Component: InputStream OutputStream Reader Writer②组件的实现类,相当于ConcreteComponent FileInputStream③装饰器接口,相当于Decorator FilterInputStream FilterOutputStream FilterRead FilterWriter④装饰器类 BufferedInputStream继承自FilterInputStream使用说明:我们可以用BufferedInputStream修饰FileInputStream
如:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); //其中file为某个具体文件的File或者FileDescription对象
再如:
FileWriter file = new FileWriter("sample.txt");BufferedWriter writer = new BufferedWriter(file);writer.write("a small amount of sample text");writer.newLine();writer.close();
特点:上述例子的特点是从一个流组合另一个流。
- 设计模式 - 装饰 Decorator
- Decorator(装饰)设计模式
- java设计模式:装饰器模式[Decorator]
- 设计模式之-Decorator--装饰器模式
- java设计模式:装饰器模式[Decorator]
- 设计模式9 - 装饰器模式Decorator
- [设计模式]装饰器模式(Decorator)
- 设计模式之: Decorator(装饰器)模式
- 设计模式(9) 装饰器模式(DECORATOR)
- [设计模式]-装饰器模式(Decorator)
- 设计模式-装饰器模式(Decorator)
- 设计模式系列-----------装饰器模式(Decorator)
- 设计模式:6. 装饰器模式(Decorator)
- 设计模式--装饰器(Decorator)模式
- 设计模式--装饰模式(Decorator)
- 设计模式---装饰模式(Decorator)
- 设计模式-Decorator装饰模式
- 设计模式 -- 装饰模式Decorator
- 回文字符串
- LibreOJ #6165. 一道水题
- 二叉树-前序遍历
- bzoj 1304(树形dp)
- 一句话概括hashMap底层
- 设计模式--装饰器(Decorator)模式
- A Simple Problem with Integers POJ
- 进程的周期Sched
- UVA 1635 Irrelevant Elements(杨辉三角+递推式求组合数+算数基本定理)
- Python学习笔记-17.09.25
- python基础 输入与输出
- Shell编程基础
- Opencv-Python :图片读取、保存、显示
- Windows10上安装tensorflow-gpu流程