Java设计模式之装饰者模式

要实现装饰者模式,注意一下几点内容:

1.装饰者类要实现真实类同样的接口

2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)

3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了装饰类的真实对象)

4.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样的方法,装饰对象可以添加一定操作在调用真实对象的方法,或者先调用真实对象的方法,再添加自己的方法)

5.不用继承,

 

先用实例说话,最后再具体装饰者模式

假设要制造添加甜蜜素和着色剂的馒头:

1.需要生产一个正常馒头

2.为节省成本(不使用玉米面),使用染色剂加入到正常馒头中

3.和面,最后生产出染色馒头

一..先实现做面包的接口

IBread接口包括准备材料,和面,蒸馒头,加工馒头(即调用前面三个步骤)

 1 package 装饰模式;
 2
 3 public interface IBread {
 4
 5     public void prepair();
 6
 7     public void kneadFlour();
 8
 9     public void steamed();
10
11     public void process();
12 }

二.制作正常馒头

 1 package 装饰模式;
 2
 3 public class NormalBread implements IBread{
 4
 5     @Override
 6     public void prepair() {
 7
 8         System.out.println("准备面粉,水以及发酵粉...");
 9     }
10
11     @Override
12     public void kneadFlour() {
13
14         System.out.println("和面...");
15     }
16
17     @Override
18     public void steamed() {
19
20         System.out.println("蒸馒头...香喷喷的馒头出炉了");
21     }
22
23     @Override
24     public void process() {
25
26         prepair();
27         kneadFlour();
28         steamed();
29     }
30
31 }

三.定义出制作面包的抽象类

抽象类实现了IBread这个制作面包的接口,同时包含IBread接口的实例

这个不是必需的,完全可以再加工是在传入IBread接口实例

但是为了通用性,添加次抽象类

对应上述的第2个注意点:装饰者类内有一个真实对象的引用

 1 package 装饰模式;
 2
 3 public abstract class AbstractBread implements IBread {
 4
 5     private final IBread bread;
 6
 7     public AbstractBread(IBread bread) {
 8         super();
 9         this.bread = bread;
10     }
11     @Override
12     public void prepair() {
13         this.bread.prepair();
14     }
15     @Override
16     public void kneadFlour() {
17         this.bread.kneadFlour();
18     }
19     @Override
20     public void steamed() {
21         this.bread.steamed();
22     }
23
24     @Override
25     public void process() {
26         prepair();
27         kneadFlour();
28         steamed();
29     }
30
31 }

四.生产有着色剂的"玉米馒头"

继承AbstarctBread类,所以可以有选择的覆盖正常生产馒头的方法,并添加原有方法原来的信息,同时也可以添加自己的方法

装饰者模式中这里最关键,

对应上述的第1个注意点:装饰者类要实现真实类同样的接口

 1 package 装饰模式;
 2
 3 public class CornDecorator extends AbstractBread{
 4
 5     public CornDecorator(IBread bread) {
 6
 7         super(bread);
 8     }
 9
10     public void paint(){
11
12         System.out.println("添加柠檬黄的着色剂");
13     }
14     @Override
15     public void kneadFlour() {
16         //添加着色剂后和面
17         this.paint();
18         super.kneadFlour();
19     }
20
21
22 }

五.生产有甜蜜素的"甜馒头"

实现与第四部一样

 1 package 装饰模式;
 2
 3 public class SweetDecorator extends AbstractBread {
 4
 5     public SweetDecorator(IBread bread) {
 6
 7         super(bread);
 8     }
 9
10     public void paint(){
11
12         System.out.println("添加甜蜜素...");
13     }
14
15     @Override
16     public void kneadFlour() {
17         //添加甜蜜素后和面
18         this.paint();
19         super.kneadFlour();
20     }
21
22 }

六.开始制作添加甜蜜素和着色剂的馒头

 1 package 装饰模式;
 2
 3 public class Client {
 4
 5     public static void main(String[] args) {
 6
 7         System.out.println("=======开始装饰馒头");
 8         IBread normalBread = new NormalBread();
 9         normalBread = new SweetDecorator(normalBread);
10         normalBread = new CornDecorator(normalBread);
11         normalBread.process();
12         System.out.println("=======装饰馒头结束");
13     }
14 }

七.输出

1 =======开始装饰馒头
2 准备面粉,水以及发酵粉...
3 添加柠檬黄的着色剂
4 添加甜蜜素...
5 和面...
6 蒸馒头...香喷喷的馒头出炉了
7 =======装饰馒头结束

装饰者模式中的4个角色

(1)被装饰者抽象Component:是一个接口或者抽象类,定义最核心的对象,这个类是装饰者的基类,例如IBread接口

(2)被装饰者具体实现ConcreteComponent:这是Component接口或抽象类的实现,例如本例中的NormalBread

(3)装饰者Decorator:一般是抽象类,实现Component,它里面必然有一个指向Component的引用,例如本例中AbstractBread

(4)装饰者实现ConcreteDecorator1和ConcreteDecorator2:用来装饰最基本的类,如本例中的CornDecorator,

JDK中的装饰者模式

java.io中很多使用了装饰者模式

举个例子:FilterInputStream继承(实现)了InputStream,同时,BufferedInputStream继承了FilterInputStream,

1,被装饰者抽象组件:即最顶层的基类InputStream

2.被装饰者具体实现ConcreteComponent:FileInputStream和FileOutputStream就是它的实现

3.装饰者Decorator:FilterInputStream中有一个InputStream的实例和构造方法传入InputStream对象

protected volatile InputStream in;

protected FilterInputStream(InputStream in) {

this.in = in;

}

4.装饰者实现:在   BufferedInputStream  中有构造方法传入InputStream对象,实现了装饰

public BufferedInputStream(InputStream in, int size) {

super(in);

if (size <= 0) {

throw new IllegalArgumentException("Buffer size <= 0");

}

buf = new byte[size];

}

这个构造方法,对比上面的做面包流程,可以惊奇的发现是一模一样的. (可以将)

1.InputStream-->IBread

(这里就是InputStream,没什么好说的)

2.FileInputStream-->NormalBread

3.FilterInputStream-->AbstractBread

(实现Component,这里是InputStram.它里面必然有一个指向Component的引用,这个引用就是InputStream的实例)

4. BufferedInputStream  --> CornDecorator

(装饰者实现,:用来装饰最基本的类,对I传入的nputStream进行了装饰)

(BufferedInputStream 的super(in)就像CornDecorator中的kneadFlour()方法,也有super.kneadFlour();,只是这里IO流中用在了构造方法 )

这就是JDK中的装饰者模式

不用继承方式实现装饰者模式的原因(以此例为说明对象,)

1.如果只是单独的添加色素或者甜蜜素确实是可以做到的,只需要将CornDecorator继承NormalBread 和SweetDecorator 继承NormalBread ,这样也能够覆盖正常制作面包的流程,添加附加的功能实现单独制作"玉米馒头"和"甜馒头".

2.如此一来,如果我们要制作甜玉米馒头(这里加点先添加甜色素,再添加玉米色素),只需要先SweetDecorator继承 NormalBread,然后CornSweetDecorator 再用继承 CornDecorator ,这样似乎是没有问题的.

2.但是想想以下的情况,如果我们希望能够在添加在添加甜色素和玉米色素中间还要加入洋葱,这要怎么做,难道说又用先SweetDecorator继承 NormalBread,然后OnionSweetDecorator继承SweetDecorator,最后再用CornOnionSweetDecorator 继承OnionSweetDecorator??

显然是不可能的,这样会导致原来代码的复用性低,而且形成了冗余的继承体系

4.使用上述实例的方法完全克服了这个问题,要实现添加洋葱,只需要实现和SweetDecorator 类似的步骤即可,最后在Client类中传入就可以实现这个功能

使用场合

1.需要为某个现有对象添加一个新的功能或职责时,可以考虑使用装饰者模式

2.某个对象的职责经常发生变化或经常需要动态添加职责,避免为了适应这种变化造成的继承扩展方式

时间: 2024-07-30 06:00:20

Java设计模式之装饰者模式的相关文章

java设计模式之 装饰器模式

适AT java设计模式之 装饰器模式 装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,动态给一个对象添提供了额外的功能. 我们通过下面的实例来演示装饰器模式的用法.模拟一个人从想吃饭.找饭店.享受美食.结束吃饭的过程 代码展示: 首先创建一个被修饰的接口 Eat package deco

java设计模式—Decorator装饰者模式

一.装饰者模式 1.定义及作用 该模式以对客户端透明的方式扩展对象的功能. 2.涉及角色      抽象构件角色:定义一个抽象接口,来规范准备附加功能的类. 具体构件角色:将要被附加功能的类,实现抽象构件角色接口. 抽象装饰者角色:持有对具体构件角色的引用并定义与抽象构件角色一致的接口. 具体装饰角色:实现抽象装饰者角色,负责为具体构件添加额外功能. 3.简单实现 抽象构件角色java 代码: package com.pattern.decorator2; /** * 抽象构件角色 * @aut

java设计模式之装饰者模式学习

装饰者模式 Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案. 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为 比如现在有个方法,是过滤文字的方法 1.接口: package com.qiao.wrapper; public interface MessageBoardHandler { public String filter(String msg); } 2.继承者 package com.qiao.w

java设计模式之装饰器模式以及在java中作用

在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用  FilterInputStream和FilterOutputStream 首先,这两个都分别是InputStream和OutputStream的子类.而且,FilterInputStream和FilterOutputStream是具体的子类,实现了InputStream和OutputStream这两个抽象类中为给出实现的方法. 但是,F

java设计模式之七装饰器模式(Decorator)

顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source im

java设计模式之装饰器模式

装饰器模式的应用场景:1.需要扩展一个类的功能.2.动态的为一个对象增加功能,而且还能动态撤销.(继承不能做到这一点,继承的功能是静态的,不能动态增删.) 源接口: 1 public interface Sourceable { 2 3 void method(); 4 } Source类: 1 public class Source implements Sourceable { 2 @Override 3 public void method() { 4 System.out.println

java 设计模式 之 装饰器模式

装饰器模式的作用 在不修改原先对象核心的功能的情况下,对功能进行增强. 增强对象的功能的途径 通过类继承的方式,对父对象进行增强操作,例如造车是父类,改装跑车,跑车加大灯,改装房车,房车加私人电影院.如图: 通过这种方式做的装饰类会因为业务的复杂性激增 2.通过装饰模式,将方法增强.如图 装饰模式架构 car :被装饰的抽象类 package javadesign.decorate; /** * 抽象小汽车 */ public interface Car { public void buildC

设计模式之装饰者模式

设计模式系列都是学习HeadFirst设计模式得出的学习心得,中间的例子也会采用书中的例子.这里有必要解释一下,在下面星巴克咖啡的例子中,有几种基本的咖啡,还有牛奶.豆浆等等可以向咖啡中添加,这里说明防止下面不懂. 今天我们来了解一下装饰者模式. 回想一下java的io包,各种stream排上倒海,初学者根本分不清楚到底怎么用,眼花缭乱.其实,它的实验遵循了装饰者设计模式.顾名思义,装饰者就可以简单的理解成用一个东西来装饰另一个东西.比如,你要做鱼吃,在你做好出国之后需要加入香菜.我们就可以简单

设计模式之装饰者模式(Decorator)

1.定义 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案 2.类图 Component抽象构件:Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象.在装饰者模式中,必然有一个最基本.最核心.最原始的接口或抽象类充当Component抽象构件. ConcreteComponent具体构件:ConcreteComponent是最核心.最原始.最基本的接口或抽象类的实现,你要装饰的就是它. Decorator装饰角色:一般是一