java设计模式之 装饰器模式
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。
这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,动态给一个对象添提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。模拟一个人从想吃饭、找饭店、享受美食、结束吃饭的过程
代码展示:
首先创建一个被修饰的接口 Eat
package decorator;
//吃饭接口
public interface Eat {
//吃饭方法
void eat();
}
创建一个被修饰者并且有自己的状态
package decorator;
public class Person implements Eat {
@Override
public void eat() {
System.out.println("======我饿了======");
}
}
创建一个修饰者的抽象类
package decorator;
public abstract class LikeEat implements Eat {
private Eat eat;
public LikeEat(Eat eat) {
this.eat=eat;
}
@Override
public void eat() {
eat.eat();
}
}
创建五个修饰类的扩展类(即--扩展修饰),分别拥有自己特定的状态,丰富被修饰的类
public class FindInMap extends LikeEat {
public FindInMap(Eat eat) {
super(eat);
}
public void userMap(){
System.out.println("打开地图寻找美食");
}
@Override
public void eat() {
super.eat();
userMap();
}
}
public class GotoRestaurant extends LikeEat {
public GotoRestaurant(Eat eat) {
super(eat);
}
public void onWay(){
System.out.println("去往饭店的路上");
}
@Override
public void eat() {
super.eat();
onWay();
}
}
public class InRestaurant extends LikeEat {
public InRestaurant(Eat eat) {
super(eat);
}
public void selectFoot(){
System.out.println("到达饭店选择食物");
}
@Override
public void eat() {
super.eat();
selectFoot();
}
}
public class EatFoot extends LikeEat {
public EatFoot(Eat eat) {
super(eat);
}
public void eating(){
System.out.println("享用美食中");
}
@Override
public void eat() {
super.eat();
eating();
}
}
public class endEat extends LikeEat {
public endEat(Eat eat) {
super(eat);
}
public void afterEat(){
System.out.println("=====美食结束=====");
}
@Override
public void eat() {
super.eat();
afterEat();
}
}
创建测试类,测试修饰效果
public class EatTest {
public static void main(String[] args) {
Eat person = new Person();
likeEat likeEat = new endEat(
new EatFoot(
new InRestaurant(
new GotoRestaurant(
new FindInMap(person))))) ;
likeEat.eat();
}
}
运行结果:

总结:
A、LikeEat抽象类中,持有Eat接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
B、LikeEat抽象类的子类(具体装饰者),里面都有一个构造方法调用super(eat),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Eat接口,只要是该Eat的实现类都可以传递进去,即表现出
likeEat likeEat = new endEat(
new EatFoot(
new InRestaurant(
new GotoRestaurant(
new FindInMap(person)))))
这种结构的样子。所以当调用likeEat.eat()的时候,又因为每个具体装饰者类中,都先调用super.eat();方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。
C、具体被装饰者,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。
D、装饰者模式的设计原则为:
对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。
使用装饰器模式--------《模拟一个电话套餐选择场景》
创建套餐账单的基本信息-----需要被修饰 的抽象类
package order;
public abstract class Order {
String name;
public String getOrder(){
return name;
}
public abstract int price();
}
创建基账单的信息类,未修饰时有自己的初始状态-----被修饰对象
package order;
public class BuyOrder extends Order {
public BuyOrder(){
name = "您选的套餐是:基本套餐";
}
public String getOrder(){
return super.getOrder();
}
public int price(){
return 10;
}
}
创建修饰基类-----一切修饰的扩展是在此基础上扩展的
package order;
//额外套餐的基础类
public abstract class BuyOrder00 extends Order { public abstract String getOrder();
}
创建修饰类的扩展类------套餐的详细修饰情况(语音+流量+短信)
package order;
public class BuyOrderNet extends BuyOrder00 {
private Order order;
public BuyOrderNet(Order order) {
super();
this.order = order;
}
@Override
public String getOrder() {
return order.getOrder()+"+上流流量套餐";
}
@Override
public int price() {
return order.price()+20;
}
}
package order;
public class BuyOrderTalk extends BuyOrder00 {
private Order order;
public BuyOrderTalk(Order order) {
super();
this.order = order;
}
@Override
public String getOrder() {
return order.getOrder()+"+语音套餐";
}
@Override
public int price() {
return order.price()+15;
}
}
package order;
public class BuyOrderMSG extends BuyOrder00 {
private Order order;
public BuyOrderMSG(Order order) {
super();
this.order = order;
}
@Override
public String getOrder() {
return order.getOrder()+"+短信套餐";
}
@Override
public int price() {
return order.price()+10;
}
}
测试用户选择的不同套餐情况
public class OrderTest {
public static void main(String[] args) {
Order order = new BuyOrder();
System.out.println(order.getOrder()+"\t月资费是:"+order.price());
BuyOrder00 order1 = new BuyOrderTalk(order);
System.out.println(order1.getOrder()+"\t月资费是:"+order1.price());
BuyOrder00 order2 = new BuyOrderNet(order);
System.out.println(order2.getOrder()+"\t月资费是:"+order2.price());
BuyOrder00 order3 = new BuyOrderMSG(order);
System.out.println(order3.getOrder()+"\t月资费是:"+order3.price());
BuyOrder00 order4 = new BuyOrderMSG(order2);
System.out.println(order4.getOrder()+"\t月资费是:"+order4.price());
BuyOrder00 order5 = new BuyOrderMSG(order1);
System.out.println(order5.getOrder()+"\t月资费是:"+order5.price());
BuyOrder00 order6 = new BuyOrderNet(order1);
System.out.println(order6.getOrder()+"\t月资费是:"+order6.price());
BuyOrder00 order7 = new BuyOrderNet(new BuyOrderMSG(new BuyOrderTalk(order)));
System.out.println(order7.getOrder()+"\t月资费是:"+order7.price());
}
}
运行结果

建议多打几个断点观察流程情况,一边更好的理解装饰器模式的工作流程
java设计模式之 装饰器模式的更多相关文章
- Java设计模式系列-装饰器模式
原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...
- java设计模式之七装饰器模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...
- Java设计模式之装饰器模式
1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...
- java设计模式之装饰器模式以及在java中作用
在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用 FilterInputStream和F ...
- java 设计模式 之 装饰器模式
装饰器模式的作用 在不修改原先对象核心的功能的情况下,对功能进行增强. 增强对象的功能的途径 通过类继承的方式,对父对象进行增强操作,例如造车是父类,改装跑车,跑车加大灯,改装房车,房车加私人电影院. ...
- Java 设计模式泛谈&装饰者模式和单例模式
设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...
- Java设计模式 - - 单例模式 装饰者模式
Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...
- python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
- PHP设计模式之装饰器模式(Decorator)
PHP设计模式之装饰器模式(Decorator) 装饰器模式 装饰器模式允许我们给一个类添加新的功能,而不改变其原有的结构.这种类型的类属于结构类,它是作为现有的类的一个包装 装饰器模式的应用场景 当 ...
随机推荐
- 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的
题目: 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的 据说这道题是百度校招的一道算法题,反正我觉得我在学校的时候很可 ...
- AngularJS创建新指令 - 函数功能
首先先介绍下AngularJS指令下的几种函数 Link函数和Scope 指令生成出的模板其实没有太多意义,除非它在特定的scope下编译.默认情况下,指令并不会创建新的子scope.更多的,它使用父 ...
- JDK源码之PriorityQueue源码剖析
除特别注明外,本站所有文章均为原创,转载请注明地址 一.优先队列的应用 优先队列在程序开发中屡见不鲜,比如操作系统在进行进程调度时一种可行的算法是使用优先队列,当一个新的进程被fork()出来后,首先 ...
- HTC开放Vive Tracker代码啦!
(52VR网2017年5月2日)HTC正在为工作室创建的Vive Tracker项目发布教程和项目文件,作为VR开发人员的新资源. 该公司希望能够让更多的开发者能够在开发Vive VR耳机时制作自己的 ...
- 蓝桥杯-大衍数列-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- IO和socket编程
五一假期结束了,突然想到3周前去上班的路上看到槐花开的正好.放假也没能采些做槐花糕,到下周肯定就老了.一年就开一次的东西,比如牡丹,花期也就一周.而花开之时,玫瑰和月季无法与之相比.明日黄花蝶也愁.想 ...
- STL容器之优先队列(转)
STL容器之优先队列 原地址:http://www.cnblogs.com/summerRQ/articles/2470130.html 优先级队列,以前刷题的时候用的比较熟,现在竟然我只能记得它的关 ...
- poj3020二分图匹配
The Global Aerial Research Centre has been allotted the task of building the fifth generation of mob ...
- React入门---组件-4
组件:网页可以分为多个模块,比如头部,底部,分享等各种模块,这些模块在其他页面也可能会用到,我们把这些分开,每一个模块当作一个组件,进行复用. 接下来直接以头部 header作为一个组件来进行demo ...
- Linux学习第一步(虚拟机的和镜像文件的安装)
一.安装虚拟机(本文以vmware workstation 12为例) 1.在网上所有虚拟机并下载. 2.找到下载文件安装好 3.一直下一步 4.接下来的就是选择安装的目录了,当然如果你的电脑c盘够大 ...