Java装饰器设计模式_动力节点Java学院整理

定义:

动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。

要点:

装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为

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

 //定义被装饰者
 public interface Human {
  public void wearClothes();
  public void walkToWhere();
 }
 //定义装饰者
 public abstract class Decorator implements Human {
  private Human human;
  public Decorator(Human human) {
   this.human = human;
  }
  public void wearClothes() {
   human.wearClothes();
  }
  public void walkToWhere() {
   human.walkToWhere();
  }
 }
 //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多
 public class Decorator_zero extends Decorator {
  public Decorator_zero(Human human) {
   super(human);
  }
  public void goHome() {
   System.out.println("进房子。。");
  }
  public void findMap() {
   System.out.println("书房找找Map。。");
  }
  @Override
  public void wearClothes() {
   // TODO Auto-generated method stub
   super.wearClothes();
   goHome();
  }
   @Override
  public void walkToWhere() {
   // TODO Auto-generated method stub
   super.walkToWhere();
   findMap();
  }
 }
 public class Decorator_first extends Decorator {
  public Decorator_first(Human human) {
   super(human);
  }
  public void goClothespress() {
   System.out.println("去衣柜找找看。。");
  }
  public void findPlaceOnMap() {
   System.out.println("在Map上找找。。");
  }
  @Override
  public void wearClothes() {
   // TODO Auto-generated method stub
   super.wearClothes();
   goClothespress();
     }
  @Override
  public void walkToWhere() {
   // TODO Auto-generated method stub
   super.walkToWhere();
   findPlaceOnMap();
  }
 }
 public class Decorator_two extends Decorator {
  public Decorator_two(Human human) {
   super(human);
  }
  public void findClothes() {
   System.out.println("找到一件D&G。。");
  }
  public void findTheTarget() {
   System.out.println("在Map上找到神秘花园和城堡。。");
  }
  @Override
  public void wearClothes() {
   // TODO Auto-generated method stub
   super.wearClothes();
   findClothes();
  }
  @Override
  public void walkToWhere() {
   // TODO Auto-generated method stub
   super.walkToWhere();
   findTheTarget();
  }
 }
 //定义被装饰者,被装饰者初始状态有些自己的装饰
 public class Person implements Human {
  @Override
  public void wearClothes() {
   // TODO Auto-generated method stub
   System.out.println("穿什么呢。。");
  }
  @Override
  public void walkToWhere() {
   // TODO Auto-generated method stub
   System.out.println("去哪里呢。。");
  }
 }
 //测试类,看一下你就会发现,跟java的I/O操作有多么相似
 public class Test {
  public static void main(String[] args) {
   Human person = new Person();
   Decorator decorator = new Decorator_two(new Decorator_first(
     new Decorator_zero(person)));
   decorator.wearClothes();
   decorator.walkToWhere();
  }
 }

运行结果:

其实就是进房子找衣服,然后找地图这样一个过程,通过装饰者的三层装饰,把细节变得丰富。

关键点:

1、Decorator抽象类中,持有Human接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。

2、Decorator抽象类的子类(具体装饰者),里面都有一个构造方法调用super(human),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Human接口,只要是该Human的实现类都可以传递进去,即表现出Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human)));这种结构的样子。所以当调用dt.wearClothes();dt.walkToWhere()的时候,又因为每个具体装饰者类中,都先调用super.wearClothes和super.walkToWhere()方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。

3、具体被装饰者类,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。

4、装饰者模式的设计原则为:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。所以:扩展体现在继承、修改体现在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则,这是自己理解的装饰者模式。

说的不清楚,有些只可意会不可言传的感觉,多看几遍代码,然后自己敲出来运行一下,基本上就领悟了。

下面这个例子也有助于理解 装饰的流程和作用
现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。

汉堡基类(被装饰者,相当于上面的Human)

package decorator;
 public abstract class Humburger {
  protected String name ;
  public String getName(){
   return name;
  }
  public abstract double getPrice();
 } 

鸡腿堡类(被装饰者的初始状态,有些自己的简单装饰,相当于上面的Person)

 package decorator;
 public class ChickenBurger extends Humburger {
  public ChickenBurger(){
   name = "鸡腿堡";
  }
  @Override
  public double getPrice() {
   return 10;
  }
 } 

配料的基类(装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料,相当于上面Decorator)

package decorator;
 public abstract class Condiment extends Humburger {
  public abstract String getName();
 } 

生菜(装饰者的第一层,相当于上面的decorator_zero)

package decorator;
 public class Lettuce extends Condiment {
  Humburger humburger;
  public Lettuce(Humburger humburger){
   this.humburger = humburger;
  }
  @Override
  public String getName() {
   return humburger.getName()+" 加生菜";
  }
  @Override
  public double getPrice() {
   return humburger.getPrice()+1.5;
  }
 } 

辣椒(装饰者的第二层,相当于上面的decorator_first)

package decorator;
 public class Chilli extends Condiment { 

  Humburger humburger;
  public Chilli(Humburger humburger){
   this.humburger = humburger;
  }
  @Override
  public String getName() {
   return humburger.getName()+" 加辣椒";
  }
  @Override
  public double getPrice() {
   return humburger.getPrice(); //辣椒是免费的哦
  }
 } 

测试类

package decorator;
 public class Test {
  /**
  * @param args
  */
  public static void main(String[] args) {
   Humburger humburger = new ChickenBurger();
   System.out.println(humburger.getName()+" 价钱:"+humburger.getPrice());
   Lettuce lettuce = new Lettuce(humburger);
   System.out.println(lettuce.getName()+" 价钱:"+lettuce.getPrice());
   Chilli chilli = new Chilli(humburger);
   System.out.println(chilli.getName()+" 价钱:"+chilli.getPrice());
   Chilli chilli2 = new Chilli(lettuce);
   System.out.println(chilli2.getName()+" 价钱:"+chilli2.getPrice());
  }
 } 

输出

鸡腿堡  价钱:10.0   
 鸡腿堡 加生菜  价钱:11.5   
 鸡腿堡 加辣椒  价钱:10.0   
 鸡腿堡 加生菜 加辣椒  价钱:11.5

以上所述是小编给大家介绍的Java装饰器设计模式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Java装饰器设计模式初探

    本篇随笔主要介绍用Java实现简单的装饰器设计模式: 先来看一下装饰器设计模式的类图: 从图中可以看到,我们可以装饰Component接口的任何实现类,而这些实现类也包括了装饰器本身,装饰器本身也可以再被装饰. 下面是用Java实现的简单的装饰器设计模式,提供的是从基本的加入咖啡入手,可以继续加入牛奶,巧克力,糖的装饰器系统. interface Component { void method(); } class Coffee implements Component { @Override

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

    概述 装饰模式是对客户端以透明的方式扩展对象的功能,是继承关系的一个替代方案.也就是说,客户端并不会觉得对象在装饰前和装饰后有什么不同,装饰模式可以在不用创造更多子类的情况下,将对象的功能加以扩展,装饰模式的关键在于这种扩展是完全透明的. 模式的结构 UML类图: 装饰模式中的类角色: 抽象构件角色(Project):给出一个接口,以规范准备接收附加责任的对象 具体构件角色(Employe):定义一个将要接收附加责任的类 装饰角色(Manager):持有一个构件对象的实例,并定义一个与抽象构件接

  • Java装饰器设计模式_动力节点Java学院整理

    定义: 动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的. 要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为 实际上Java 的I/O API就是使用Decorator实现的. //定义被装

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java接口的作用_动力节点Java学院整理

    1. 接口是一种规范 很好,你已经知道接口是一种规范了! 下面这张图是我们生活中遇到的接口:电源插座接口. 2. 为什么需要规范呢? 因为有了接口规范: • 任何电器只有有符合规范的插头,就可以获得电力 • 任何厂家(西门子插座,TCL插座,公牛插座...)按照规范进行制作,就能进行供电 每个厂家插座的生产技术.工艺都不一样,因为接口的implementation可以不一样,但是并不影响电器的正常工作.插座的内部实现对于电器来说是完全屏蔽的. 对于软件开发同样也是类似的: • 按照接口规范进行方

  • Java数组的特性_动力节点Java学院整理

    Java中的数组是对象吗? Java和C++都是面向对象的语言.在使用这些语言的时候,我们可以直接使用标准的类库,也可以使用组合和继承等面向对象的特性构建自己的类,并且根据自己构建的类创建对象.那么,我们是不是应该考虑这样一个问题:在面向对象的语言中,数组是对象吗? 要判断数组是不是对象,那么首先明确什么是对象,也就是对象的定义.在较高的层面上,对象是根据某个类创建出来的一个实例,表示某类事物中一个具体的个体.对象具有各种属性,并且具有一些特定的行为.而在较低的层面上,站在计算机的角度,对象就是

  • Java 中HashCode作用_动力节点Java学院整理

    第1 部分 hashCode的作用 Java集合中有两类,一类是List,一类是Set他们之间的区别就在于List集合中的元素师有序的,且可以重复,而Set集合中元素是无序不可重复的.对于List好处理,但是对于Set而言我们要如何来保证元素不重复呢?通过迭代来equals()是否相等.数据量小还可以接受,当我们的数据量大的时候效率可想而知(当然我们可以利用算法进行优化).比如我们向HashSet插入1000数据,难道我们真的要迭代1000次,调用1000次equals()方法吗?hashCod

  • Java字符编码简介_动力节点Java学院整理

    1. 概述 本文主要包括以下几个方面:编码基本知识,Java,系统软件,url,工具软件等. 在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是"d6d0 cec4",Unicode编码为"4e2d 6587",UTF编码就是"e4b8ad e69687".注意,这两个字没有iso8859-1编码,但可以用iso8859-1编码来"表示". 2. 编码基本知识 最早的编码是iso88

  • Java Socket编程笔记_动力节点Java学院整理

    对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求.这会,Socket对于我们来说就非常实用了.下面是本次学习的笔记.主要分异常类型.交互原理.Socket.ServerSocket.多线程这几个方面阐述. 异常类型 在了解Socket的内容之前,先要了解一下涉及到的一些异常类型.以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可. UnkownHostException:    主机名字或IP错误 ConnectException

  • Java 多线程并发编程_动力节点Java学院整理

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关的API,进程主要包括表示进程的jav

  • Java日志相关技术_动力节点Java学院整理

    Java日志相关技术 作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在运行维护阶段,日志系统又可以帮我们记录大部分的异常信息,从而帮助我们更好的完善系统.本文要来分享一些Java程序员最常用的Java日志框架组件. 1.log4j – 最受欢迎的Java日志组件 Log4j是一款基于Java的开源日志组件,Log4j功能非常强大,我们可以将日志信

  • Java concurrency之集合_动力节点Java学院整理

    Java集合包 Java集合主体内容包括Collection集合和Map类:而Collection集合又可以划分为List(队列)和Set(集合). 1. List的实现类主要有: LinkedList, ArrayList, Vector, Stack. (01) LinkedList是双向链表实现的双端队列:它不是线程安全的,只适用于单线程. (02) ArrayList是数组实现的队列,它是一个动态数组:它也不是线程安全的,只适用于单线程. (03) Vector是数组实现的矢量队列,它也

随机推荐