首先,什么是装饰者模式呢???

  装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。他是23种设计模式之一,英文叫Decorator Pattern,又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

  为什么要使用装饰模式

  1. 多用组合,少用继承。
    利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
  2. 类应设计的对扩展开放,对修改关闭。
 

  之前我们假如实现这样一个功能,建造出各种各样不同功能的车,咱们是这样实现的:

  首先,新建一个Car接口,定义了所有车的基本功能,就是跑run(),和展示自己功能的方法show(),

 public interface Car {
public void show();
public void run();
}

  然后,在创建各个具体的车实现Car接口

  会跑的车

 public class RunCar  implements Car{

     @Override
public void show() {
this.run(); } @Override
public void run() {
System.out.println("可以跑"); }
}

  会游泳的车

 public class SwimCar implements Car {

     @Override
public void show() {
this.run();
this.swim();
} @Override
public void run() {
System.out.println("可以跑"); } public void swim(){
System.out.println("可以游泳");
}
}

  会飞的车

 public class FlyCar implements Car {

     @Override
public void show() {
this.run();
this.fly();
} @Override
public void run() {
System.out.println("可以跑"); } public void fly(){
System.out.println("可以飞");
}
}

  这时,写一个客户端展示每个车的功能

 public class MainClass {
public static void main(String[] args) {
// Car car = new RunCar();
// Car car = new FlyCar();
Car car = new SwimCar();
car.show();
}
}

  这样,每新增一种车,就要新写一个子类实现或继承其他类或接口,就相当于,每新增一种功能,就要新建一辆车。

  这时,我们还有一种替代方案,就是使用装饰模式

  首先,新建一个Car接口,和一个基础的Car的实现类RunCar,因为只要是车一定有跑的功能,这两个和上面一样,不在重复写了。

  然后在新建装饰类,不同的功能建不同的装饰类

  1、新建一个装饰类父类,实现Car接口,提供一个有参的构造方法,共有的方法show(),私有的Car成员变量,并为之提供get(),set()方法。

  一定要继承Car,因为装饰过后,还是一辆车

 public abstract class CarDecorator implements Car{
private Car car; public CarDecorator(Car car){
this.car = car;
} public Car getCar() {
return car;
} public void setCar(Car car) {
this.car = car;
} public abstract void show();
}

  2、为不同的装饰新建装饰类,并继承CarDecorator抽象类

  (1)游泳装饰类,覆盖抽象方法,在新增特有的方法

 public class SwimCarDecorator extends CarDecorator {

     public SwimCarDecorator(Car car){
super(car);
} @Override
public void show() {
this.getCar().show();
this.swim();
} public void swim(){
System.out.println("可以游泳");
} @Override
public void run() {
}
}

  (2)飞行装饰类

 public class FlyCarDecorator extends CarDecorator {

     public FlyCarDecorator(Car car){
super(car);
}
@Override
public void show() {
this.getCar().show();
this.fly();
} public void fly(){
System.out.println("可以飞");
} @Override
public void run() {
}
}

  添加客户端,执行

public class MainClass {
public static void main(String[] args) {
Car car = new RunCar();
Car swimCar = new SwimCarDecorator(car);
swimCar.show();
} }

  这样,就不等于是,每新增一个功能就新建一辆车了,而是基础有一个RunCar,这是最基本的车,装饰类就相当于在基本的车的基础上,添加功能,装饰这台最基本的车。

  所以一定要继承Car,因为装饰过后,还是一辆车,我们可以直接Car swimCar = new SwimCarDecorator(car);用Car来创建变量。

  同样,继承关系如果每一个功能都要添加一个新的子类,如果,一辆车已经拥有了游泳和飞行的功能,这时有新增同时拥有游泳和飞行的Car,继承关系就需要在新建一个子类同时拥有这两个功能,而装饰模式什么都不需要新增,对基础的RunCar修饰两遍即可。像这样:

public class MainClass {
public static void main(String[] args) {
Car car = new RunCar();
Car swimCar = new SwimCarDecorator(car);
Car flySwimCar = new FlyCarDecorator(swimCar);
flySwimCar.show();
}
}

  这样子,最后的flySwimCar就同时拥有了飞行和游泳的功能,这也是装饰类继承Car的原因,这样子装饰类才能当做参数放进构造方法中。

  

装饰模式的结构图

  装饰模式的角色与职责:

  1、抽象组件角色(Component): 一个抽象接口,是被装饰类和装饰类的父接口。(Car)

  2、具体组件角色(ConcreteComponent):为抽象组件的实现类。(RunCar)

  3、抽象装饰角色(Decorator):包含一个组件的引用,并定义了与抽象组件一致的接口。(CarDecorator)

  4、具体装饰角色(ConcreteDecorator):为抽象装饰角色的实现类。负责具体的装饰。(FlyCarDecorator、SwimCarDecorator)

  使用范围

  以下情况使用Decorator模式
  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

  装饰模式的优缺点

  优点

    1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
    2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

  缺点

    1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
    2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
    3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

java设计模式-----7、装饰模式的更多相关文章

  1. java设计模式之装饰模式

    发现设计模式的学习越来越让自己学习的东西太少了,应该多接触一些东西,多出去走一走. 装饰模式概念: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活(大话设计模式) 在不 ...

  2. Java——设计模式(装饰模式_IO)

     /* * 装饰设计模式: *  对一组对象的功能进行增强时,就可以使用该模式进行问题的解决; * 装饰和继承都能实现一样的特点:  就是进行功能的扩转增强. * */ public class  ...

  3. JAVA设计模式:装饰模式

    前面我们学习了代理模式: 代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你 ...

  4. java设计模式(装饰模式)

    装饰模式实现了可以动态地为原对象扩展方法 装饰对象与被装饰的都实现了同一个接口(或抽象类) 举个例子: 工作 可以边吃东西边工作,也可以边喝东西边工作,还可以工作的时候边吃边喝 创建共同接口 Work ...

  5. Java设计模式之装饰模式趣谈

    本文由码农网 – 鲁阿皓原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 前情提要:http://blog.csdn.net/baidu_30889437/article/details/ ...

  6. Java设计模式学习记录-装饰模式

    前言 装饰模式也是一种结构型模式,主要是目的是相对于类与类之间的继承关系来说,使用装饰模式可以降低耦合度.JDK中有不少地方都使用到了装饰模式,例如Java的各种I/O流,javax.swing包中一 ...

  7. Java设计模式(7)装饰模式(Decorator模式)

    Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这 ...

  8. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  9. Java设计模式(十二) 策略模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...

  10. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

随机推荐

  1. tomcat 线程模型

    最近看到了内网ATA上的一篇断网故障时Mtop触发tomcat高并发场景下的BUG排查和修复(已被apache采纳),引起了我的好奇,感觉原作者对应底层十分了解,写的很复杂.原来对于tomcat的线程 ...

  2. Linux 环境变量加强

    Linux 环境变量加强 # 前言 今天,主要是之前搭建 GO 环境包的使用发现自己对 Linux 环境变量还不是很熟悉. 遇到环境变量的问题还是会有些懵逼.所以,今天写点Linux 环境变量的文章, ...

  3. Nginx采用yum安装-Carr

    (1)使用yum安装nginx需要包括Nginx的库,安装Nginx的库 #rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx- ...

  4. 把 Reative Native 47 版本集成到已有的 Native iOS 工程中

    一.搭建开发环境 http://reactnative.cn/docs/0.46/getting-started.html#content 二.创建一个模板 运行以下命令,创建一个最新版本的 reac ...

  5. SYN 洪泛攻击

    在 TCP 三次握手中,服务器为了响应一个收到的 SYN,分配并初始化连接变量和缓存.然后服务器发送一个 SYNACK 进行相应,并等待来自客户的 ACK 报文段. 如果某客户不发送 ACK 来完成三 ...

  6. SpringBoot 整合 中国移动 MAS HTTP1.0 实现短信发送服务

    因为客户需要,本身使用的 阿里云的短信服务改为了中国移动MAS HTTP 1.0  短信通知,因为看到网络上关于此类的博客知识很少,再趟完坑后特地写下这篇博客,提醒后来人. 特别感谢 中国移动MAS ...

  7. Hadoop 3.1.2 下载安装和分布式搭建的准备

    官方有详细文档:https://hadoop.apache.org/docs/r3.1.2/hadoop-project-dist/hadoop-common/SingleCluster.html 我 ...

  8. (转)C# 正则表达式

    最近写爬虫时需要用到正则表达式,有段时间没有使用正则表达式现在渐渐感觉有些淡忘,现在使用还需要去查询一些资料.为了避免以后这样的情况,在此记录下正则表达式的一些基本使用方法附带小的实例.让以后在使用时 ...

  9. redux进阶 --- 中间件和异步操作

    你为什么需要异步操作? https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in ...

  10. SpringSecurity之记住我功能的实现

    Spring security记住我基本原理: 登录的时候,请求发送给过滤器UsernamePasswordAuthenticationFilter,当该过滤器认证成功后,会调用RememberMeS ...