Java 设计模式之 -- 装饰者模式

对于装饰模式我们先看官方的介绍

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。由于java的封装继承多态三个特性使得我们充分扩展父类的功能,装饰者模式就是建立在这样的基础上的。设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。为了更好的说明装饰模式的使用,下面引用下面博主的举例,相关链接

http://blog.csdn.net/jason0539/article/details/22713711

实际上Java 的I/O API就是使用Decorator实现的。

[java] view plain copy

 print ?
  1. //定义被装饰者  
  2. public interface Human {  
  3.     public void wearClothes();  
  4.   
  5.     public void walkToWhere();  
  6. }  
  7.   
  8. //定义装饰者  
  9. public abstract class Decorator implements Human {  
  10.     private Human human;  
  11.   
  12.     public Decorator(Human human) {  
  13.         this.human = human;  
  14.     }  
  15.   
  16.     public void wearClothes() {  
  17.         human.wearClothes();  
  18.     }  
  19.   
  20.     public void walkToWhere() {  
  21.         human.walkToWhere();  
  22.     }  
  23. }  
  24.   
  25. //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多  
  26. public class Decorator_zero extends Decorator {  
  27.   
  28.     public Decorator_zero(Human human) {  
  29.         super(human);  
  30.     }  
  31.   
  32.     public void goHome() {  
  33.         System.out.println("进房子。。");  
  34.     }  
  35.   
  36.     public void findMap() {  
  37.         System.out.println("书房找找Map。。");  
  38.     }  
  39.   
  40.     @Override  
  41.     public void wearClothes() {  
  42.         // TODO Auto-generated method stub  
  43.         super.wearClothes();  
  44.         goHome();  
  45.     }  
  46.   
  47.     @Override  
  48.     public void walkToWhere() {  
  49.         // TODO Auto-generated method stub  
  50.         super.walkToWhere();  
  51.         findMap();  
  52.     }  
  53. }  
  54.   
  55. public class Decorator_first extends Decorator {  
  56.   
  57.     public Decorator_first(Human human) {  
  58.         super(human);  
  59.     }  
  60.   
  61.     public void goClothespress() {  
  62.         System.out.println("去衣柜找找看。。");  
  63.     }  
  64.   
  65.     public void findPlaceOnMap() {  
  66.         System.out.println("在Map上找找。。");  
  67.     }  
  68.   
  69.     @Override  
  70.     public void wearClothes() {  
  71.         // TODO Auto-generated method stub  
  72.         super.wearClothes();  
  73.         goClothespress();  
  74.     }  
  75.   
  76.     @Override  
  77.     public void walkToWhere() {  
  78.         // TODO Auto-generated method stub  
  79.         super.walkToWhere();  
  80.         findPlaceOnMap();  
  81.     }  
  82. }  
  83.   
  84. public class Decorator_two extends Decorator {  
  85.   
  86.     public Decorator_two(Human human) {  
  87.         super(human);  
  88.     }  
  89.   
  90.     public void findClothes() {  
  91.         System.out.println("找到一件D&G。。");  
  92.     }  
  93.   
  94.     public void findTheTarget() {  
  95.         System.out.println("在Map上找到神秘花园和城堡。。");  
  96.     }  
  97.   
  98.     @Override  
  99.     public void wearClothes() {  
  100.         // TODO Auto-generated method stub  
  101.         super.wearClothes();  
  102.         findClothes();  
  103.     }  
  104.   
  105.     @Override  
  106.     public void walkToWhere() {  
  107.         // TODO Auto-generated method stub  
  108.         super.walkToWhere();  
  109.         findTheTarget();  
  110.     }  
  111. }  
  112.   
  113. //定义被装饰者,被装饰者初始状态有些自己的装饰  
  114. public class Person implements Human {  
  115.   
  116.     @Override  
  117.     public void wearClothes() {  
  118.         // TODO Auto-generated method stub  
  119.         System.out.println("穿什么呢。。");  
  120.     }  
  121.   
  122.     @Override  
  123.     public void walkToWhere() {  
  124.         // TODO Auto-generated method stub  
  125.         System.out.println("去哪里呢。。");  
  126.     }  
  127. }  
  128. //测试类,看一下你就会发现,跟java的I/O操作有多么相似  
  129. public class Test {  
  130.     public static void main(String[] args) {  
  131.         Human person = new Person();  
  132.         Decorator decorator = new Decorator_two(new Decorator_first(  
  133.                 new Decorator_zero(person)));  
  134.         decorator.wearClothes();  
  135.         decorator.walkToWhere();  
  136.     }  
  137. }  

运行结果:


UML类图

我们现在来看看装饰者模式的 uml 类图:
这里写图片描述
装饰者模式共有四大角色:

    • Component:抽象组件

可以是一个接口或者是抽象类,其充当的就是被装饰的原始对象,用来定义装饰者和被装饰者的基本行为。

    • ConcreteComponent:组件具体实现类

该类是 Component 类的基本实现,也是我们装饰的具体对象。

    • Decorator:抽象装饰者

装饰组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。当然,如果是装饰逻辑单一,只有一个的情况下我们可以忽略该类直接作为具体的装饰者。

    • ConcreteDecoratorA 和 ConcreteDecoratorB:装饰者具体实现类

对抽象装饰者的具体实现。

在已有的 Component 和 ConcreteComponent 体系下,实现装饰者模式来扩展原有系统的功能,可以分为 5 个步骤

  1. 继承或者实现 Component 组件,生成一个 Decorator 装饰者抽象类;
  2. 在生成的这个 Decorator 装饰者类中,增加一个 Component 的私有成员对象;
  3. 将 ConcreteComponent 或者其他需要被装饰的对象传入 Decorator 类中并赋值给上一步的 Component 对象;
  4. 在装饰者 Decorator 类中,将所有的操作都替换成该 Component 对象的对应操作;
  5. 在 ConcreteDecorator 类中,根据需要对应覆盖需要重写的方法。

装饰者模式在源码中用的也是非常多的,在 Java 和 Android 中都能够见到装饰者模式的影子:

Java 中的装饰者模式

最典型的就是 Java 中的 java.io 包下面的 InputStream 和 OutputStream 相关类了,初学 Java 的时候,看到这些类,头都大了,其实学了装饰者模式之后,再理解这些类就很简单了,画一个简单的类图来表示:
这里写图片描述
InputStream 类是一个抽象组件, FileInputStream,StringBufferInputStream 和 ByteArrayInputStream 类都是可以被装饰者包起来的具体组件;FilterInputStream 是一个抽象装饰者,所以它的四个子类都是一个个装饰者了。

Android 中的装饰者模式

其次,对于 android 开发工程师来说,最最重要的就应该是“上帝类” Context 和其子类了,这些类我就不用解释了,上一张类图基本就明确了:
这里写图片描述
所以对于 Application,Activity 和 Service 等类来说,他们只是一个个装饰者,都是用来装饰 ContextImpl 这个被装饰者类,Application 是在 createBaseContextForActivity 方法中,通过 ContextImpl 的静态方法 createActivityContext 获得一个 ContextImpl 的实例对象,并通过 setOuterContext 方法将两者建立关联;Activity 是通过 handleLaunchActivity 方法设置的 ContextImpl 实例,这个方法会获取到一个Activity对象,在performLaunchActivity函数中会调用该activity的attach方法,这个方法把一个ContextImpl对象attach到了Activity中,具体可以看看我的这篇博客,里面详细介绍到了 Activity 的启动过程:android 不能在子线程中更新ui的讨论和分析。别的类在这里就不介绍了,具体的大家可以去网上查阅相关资料。

示例与源码

我们这里以一个图形系统中的 Window 为例,一般情况窗口都是能够垂直或者是左右欢动的,所以为了能够更好的支持 Window 的滑动,给滑动的 Window 加上一个 ScrollBar 是一个不错的方法,为了重用代码,水平滑动的 Window 和垂直滑动的 Window 我们就能够使用装饰者模式去处理,基本类图如下所示:
这里写图片描述
根据类图,我们首先实现 Window 这个接口:
IWindow.class

1
2
3
4
5
6
public interface IWindow {
 
     void draw();
 
     String getDescription();
}

然后是被装饰者 SimpleWindow 类,它实现了窗口的基本行为:
SimpleWindow.class

1
2
3
4
5
6
7
8
9
10
11
public class SimpleWindow implements IWindow {
     @Override
     public void draw() {
         Log.e( "shawn" , "drawing a window" );
     }
 
     @Override
     public String getDescription() {
         return "a window" ;
     }
}

然后是装饰者类角色的抽象父类:
WindowDecorator.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class WindowDecorator implements IWindow{
 
     private IWindow window;
 
     public WindowDecorator(IWindow window) {
         this .window = window;
     }
 
     @Override
     public void draw() {
         window.draw();
     }
 
     @Override
     public String getDescription() {
         return window.getDescription();
     }
}

最后是实现该装饰者父类的装饰者子类:
HorizontalScrollBarDecorator.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HorizontalScrollBarDecorator extends WindowDecorator {
 
     public HorizontalScrollBarDecorator(IWindow window) {
         super (window);
     }
 
     @Override
     public void draw() {
         super .draw();
         Log.e( "shawn" , "then drawing the horizontal scroll bar" );
     }
 
     @Override
     public String getDescription() {
         return super .getDescription() + " with horizontal scroll bar" ;
     }
}

VerticalScrollBarDecorator.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class VerticalScrollBarDecorator extends WindowDecorator {
 
     public VerticalScrollBarDecorator(IWindow window) {
         super (window);
     }
 
     @Override
     public void draw() {
         super .draw();
         Log.e( "shawn" , "then drawing the vertical scroll bar" );
     }
 
     @Override
     public String getDescription() {
         return super .getDescription() + " with vertical scroll bar" ;
     }
}

最后测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
switch (v.getId()) {
     case R.id.btn_horizontal_window:
         IWindow horizontalWindow = new HorizontalScrollBarDecorator( new SimpleWindow());
         horizontalWindow.draw();
         Log.e( "shawn" , "window description : " + horizontalWindow.getDescription());
         break ;
     case R.id.btn_vertical_window:
         IWindow verticalWindow = new VerticalScrollBarDecorator( new SimpleWindow());
         verticalWindow.draw();
         Log.e( "shawn" , "window description : " + verticalWindow.getDescription());
         break ;
}

结果:

1
2
3
4
5
6
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the horizontal scroll bar
com.android.decoratorpattern E/shawn: window description : a window with horizontal scroll bar
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the vertical scroll bar
com.android.decoratorpattern E/shawn: window description : a window with vertical scroll bar

代码一目了然,结构清晰。
其实说到底,每一个写过 Android 程序的人都应该用过装饰者模式,因为每写一个 Activity,就相当于是写了一个装饰者类,不经意间就用了装饰者模式,大家想一想是不是,哈哈~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值