创建网站的快捷方式,高端html5网站设计工作室织梦模板 dedecms5.7,林州网站建设策划,网上自己建网站文章目录 1 装饰者模式#xff08;Decorator Pattern#xff09;1.1 介绍1.2 概述1.3 装饰者模式的结构 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析5 总结5.1 装饰者模式的优缺点5.2 装饰者模式的使用场景5.3 装饰者模式 VS 代理模式 #x… 文章目录 1 装饰者模式Decorator Pattern1.1 介绍1.2 概述1.3 装饰者模式的结构 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析5 总结5.1 装饰者模式的优缺点5.2 装饰者模式的使用场景5.3 装饰者模式 VS 代理模式 前言本文章为瑞_系列专栏之《23种设计模式》的装饰者模式篇。本文中的部分图和概念等资料来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识建议阅读 《瑞_23种设计模式_概述》 本系列 - 设计模式 - 链接《瑞_23种设计模式_概述》 ⬇️本系列 - 创建型模式 - 链接 单例模式《瑞_23种设计模式_单例模式》 工厂模式《瑞_23种设计模式_工厂模式》 原型模式《瑞_23种设计模式_原型模式》 抽象工厂模式《瑞_23种设计模式_抽象工厂模式》 建造者模式《瑞_23种设计模式_建造者模式》 ⬇️本系列 - 结构型模式 - 链接 代理模式《瑞_23种设计模式_代理模式》 适配器模式《瑞_23种设计模式_适配器模式》 装饰者模式《后续更新》 桥接模式《后续更新》 外观模式《后续更新》 组合模式《后续更新》 享元模式《后续更新》 ⬇️本系列 - 行为型模式 - 链接 模板方法模式《后续更新》 策略模式《后续更新》 命令模式《后续更新》 职责链模式《后续更新》 状态模式《后续更新》 观察者模式《后续更新》 中介者模式《后续更新》 迭代器模式《后续更新》 访问者模式《后续更新》 备忘录模式《后续更新》 解释器模式《后续更新》 1 装饰者模式Decorator Pattern 装饰者模式Decorator Pattern允许向一个现有的对象添加新的功能同时又不改变其结构。这种类型的设计模式属于结构型模式它是作为现有的类的一个包装。 瑞结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式前者采用继承机制来组织接口和类后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低满足“合成复用原则”所以对象结构型模式比类结构型模式具有更大的灵活性。 装饰者模式通过将对象包装在装饰器类中以便动态地修改其行为。 这种模式创建了一个装饰类用来包装原有的类并在保持类方法签名完整性的前提下提供了额外的功能。
1.1 介绍 意图动态地给一个对象添加一些额外的职责。就增加功能来说装饰器模式相比生成子类更为灵活。 主要解决一般的我们为了扩展一个类经常使用继承方式实现由于继承为类引入静态特征并且随着扩展功能的增多子类会很膨胀。 何时使用在不想增加很多子类的情况下扩展类。 如何解决将具体功能职责划分同时继承装饰者模式。 关键代码 1️⃣ Component 类充当抽象角色不应该具体实现。 2️⃣ 修饰类引用和继承 Component 类具体扩展类重写父类方法。 应用实例 1️⃣ 孙悟空有 72 变当他变成庙宇后他的根本还是一只猴子但是他又有了庙宇的功能。 2️⃣ 不论一幅画有没有画框都可以挂在墙上但是通常都是有画框的并且实际上是画框被挂在墙上。在挂在墙上之前画可以被蒙上玻璃装到框子里这时画、玻璃和画框形成了一个物体。 优点装饰类和被装饰类可以独立发展不会相互耦合装饰模式是继承的一个替代模式装饰模式可以动态扩展一个实现类的功能。 缺点多层装饰比较复杂。 使用场景 1️⃣ 扩展一个类的功能。 2️⃣ 动态增加功能动态撤销。 注意事项可代替继承。
1.2 概述 定义指在不改变现有对象结构的情况下动态地给该对象增加一些职责即增加其额外功能的模式。 先看一个快餐店的例子 快餐店有炒面、炒饭这些快餐可以额外附加鸡蛋、火腿、培根这些配菜当然加配菜需要额外加钱每个配菜的价钱通常不太一样那么计算总价就会显得比较麻烦。 该需求类图如下未使用装饰者模式设计 使用继承的方式存在的问题 扩展性不好 如果要再加一种配料火腿肠我们就会发现需要给 FriedRice 和 FriedNoodles 分别定义一个子类。如果要新增一个快餐品类炒河粉的话就需要定义更多的子类。 产生过多的子类
1.3 装饰者模式的结构
装饰Decorator模式中的角色 1️⃣ 抽象构件Component角色 定义一个抽象接口以规范准备接收附加责任的对象。 2️⃣ 具体构件Concrete Component角色 实现抽象构件通过装饰角色为其添加一些职责。 3️⃣抽象装饰Decorator角色 继承或实现抽象构件并包含具体构件的实例可以通过其子类扩展具体构件的功能。 4️⃣ 具体装饰ConcreteDecorator角色 实现抽象装饰的相关方法并给具体构件对象添加附加的责任。 2 案例一 快餐店 2.1 需求 使用装饰者模式对快餐店案例点我跳转进行改进体会装饰者模式的精髓。 使用装饰者模式设计后的类图如下 2.2 代码实现
快餐类抽象类 /*** 快餐类(抽象构件角色)** author LiaoYuXing-Ray**/
public abstract class FastFood {// 价格private float price;// 描述private String desc;public float getPrice() {return price;}public void setPrice(float price) {this.price price;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc desc;}public FastFood(float price, String desc) {this.price price;this.desc desc;}public FastFood() {}// 计算价格public abstract float cost();
}炒饭类 /*** 炒饭(具体构件角色)** author LiaoYuXing-Ray**/
public class FriedRice extends FastFood {public FriedRice() {super(10, 炒饭);}public float cost() {return getPrice();}
}
炒面类 /*** 炒面(具体的构件角色)** author LiaoYuXing-Ray**/
public class FriedNoodles extends FastFood {public FriedNoodles() {super(12,炒面);}public float cost() {return getPrice();}
}装饰者类抽象类 /*** 装饰者类(抽象装饰者角色)** author LiaoYuXing-Ray**/
public abstract class Garnish extends FastFood {// 声明快餐类的变量private FastFood fastFood;public FastFood getFastFood() {return fastFood;}public void setFastFood(FastFood fastFood) {this.fastFood fastFood;}public Garnish(FastFood fastFood,float price, String desc) {super(price, desc);this.fastFood fastFood;}
}鸡蛋类类 /*** 鸡蛋类(具体的装饰者角色)** author LiaoYuXing-Ray**/
public class Egg extends Garnish {public Egg(FastFood fastFood) {super(fastFood,1,鸡蛋);}public float cost() {//计算价格return getPrice() getFastFood().cost();}Overridepublic String getDesc() {return super.getDesc() getFastFood().getDesc();}
}培根类类 /*** 培根类(具体的装饰者角色)** author LiaoYuXing-Ray**/
public class Bacon extends Garnish {public Bacon(FastFood fastFood) {super(fastFood,2,培根);}public float cost() {//计算价格return getPrice() getFastFood().cost();}Overridepublic String getDesc() {return super.getDesc() getFastFood().getDesc();}
}测试类 /*** 测试类** author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 点一份炒饭FastFood food new FriedRice();System.out.println(food.getDesc() food.cost() 元);System.out.println();// 在上面的炒饭中加一个鸡蛋food new Egg(food);System.out.println(food.getDesc() food.cost() 元);System.out.println();// 再加一个鸡蛋food new Egg(food);System.out.println(food.getDesc() food.cost() 元);System.out.println();food new Bacon(food);System.out.println(food.getDesc() food.cost() 元);}
}代码运行结果如下 炒饭 10.0元鸡蛋炒饭 11.0元鸡蛋鸡蛋炒饭 12.0元培根鸡蛋鸡蛋炒饭 14.0元好处
饰者模式可以带来比继承更加灵活性的扩展功能使用更加方便可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性完美的遵循开闭原则继承是静态的附加责任装饰者则是动态的附加责任。装饰类和被装饰类可以独立发展不会相互耦合装饰模式是继承的一个替代模式装饰模式可以动态扩展一个实现类的功能。 3 案例二 本案例为菜鸟教程中的案例 3.1 需求 把一个形状装饰上不同的颜色同时又不改变形状类 创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator并把 Shape 对象作为它的实例变量。 RedShapeDecorator 是实现了 ShapeDecorator 的实体类。 DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。 3.2 代码实现 步骤1 创建一个接口。
Shape.java public interface Shape {void draw();
}步骤2 创建实现接口的实体类。
Rectangle.java public class Rectangle implements Shape {Overridepublic void draw() {System.out.println(Shape: Rectangle);}
}Circle.java public class Circle implements Shape {Overridepublic void draw() {System.out.println(Shape: Circle);}
}步骤3 创建实现了 Shape 接口的抽象装饰类。
ShapeDecorator.java public abstract class ShapeDecorator implements Shape {protected Shape decoratedShape;public ShapeDecorator(Shape decoratedShape){this.decoratedShape decoratedShape;}public void draw(){decoratedShape.draw();}
}步骤4 创建扩展了 ShapeDecorator 类的实体装饰类。
RedShapeDecorator.java public class RedShapeDecorator extends ShapeDecorator {public RedShapeDecorator(Shape decoratedShape) {super(decoratedShape); }Overridepublic void draw() {decoratedShape.draw(); setRedBorder(decoratedShape);}private void setRedBorder(Shape decoratedShape){System.out.println(Border Color: Red);}
}步骤5 使用 RedShapeDecorator 来装饰 Shape 对象。
DecoratorPatternDemo.java public class DecoratorPatternDemo {public static void main(String[] args) {Shape circle new Circle();ShapeDecorator redCircle new RedShapeDecorator(new Circle());ShapeDecorator redRectangle new RedShapeDecorator(new Rectangle());//Shape redCircle new RedShapeDecorator(new Circle());//Shape redRectangle new RedShapeDecorator(new Rectangle());System.out.println(Circle with normal border);circle.draw();System.out.println(\nCircle of red border);redCircle.draw();System.out.println(\nRectangle of red border);redRectangle.draw();}
}步骤6
执行程序输出结果 Circle with normal borderShape: CircleCircle of red borderShape: CircleBorder Color: RedRectangle of red borderShape: RectangleBorder Color: Red4 JDK源码解析 IO流中的包装类使用到了装饰者模式。BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter。 我们以BufferedWriter举例来说明先看看如何使用BufferedWriter
public class RayTest {public static void main(String[] args) throws Exception{// 获取当前文件的绝对路径String absolutePath System.getProperty(user.dir);String filePath absolutePath File.separator test.txt;// 创建BufferedWriter对象// 创建FileWriter对象FileWriter fw new FileWriter(filePath);BufferedWriter bw new BufferedWriter(fw);// 写数据bw.write(hello Buffered);bw.close();}
}分析它们的结构类图如下使用了装饰者模式的设计思维 BufferedWriter使用装饰者模式对Writer子实现类进行了增强添加了缓冲区提高了写数据的效率。 5 总结
5.1 装饰者模式的优缺点
优点 1️⃣ 组合使用饰者模式可以带来比继承更加灵活性的扩展功能使用更加方便通过使用不同的装饰类以及这些装饰类的排列组合可以创造出很多不同行为的组合。这意味着可以使用多个装饰类来装饰同一个对象从而得到功能更为强大的对象。装饰者模式比继承更具良好的扩展性完美的遵循开闭原则继承是静态的附加责任装饰者则是动态的附加责任。 2️⃣ 动态扩展装饰类和被装饰类可以独立发展不会相互耦合装饰模式是继承的一个替代模式装饰模式可以动态扩展一个实现类的功能。 3️⃣ 符合开闭原则装饰者模式允许在不修改原有代码的情况下增加新的功能这符合开闭原则即“软件实体类、模块、函数等等应当是可扩展而不可修改的”。 4️⃣ 易于使用装饰者模式易于理解和使用因为它与日常生活中的装饰概念相似。
缺点 1️⃣ 产生大量小对象由于装饰者模式是通过创建大量的小对象来实现功能的扩展这可能会增加系统的内存开销和垃圾回收的压力。 2️⃣ 可能导致过度设计如果过度使用装饰者模式可能会导致系统中有过多的装饰类和具体的构件类从而使代码变得复杂和难以维护。 3️⃣ 可能引入额外的性能开销由于装饰者模式需要在运行时动态地组合对象这可能会引入额外的性能开销特别是在需要多层装饰的情况下。
5.2 装饰者模式的使用场景 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。 不能采用继承的情况主要有两类 第一类是系统中存在大量独立的扩展为支持每一种组合将产生大量的子类使得子类数目呈爆炸性增长第二类是因为类定义不能继承如final类 在不影响其他对象的情况下以动态、透明的方式给单个对象添加职责。 当对象的功能要求可以动态地添加也可以再动态地撤销时。在面向服务的架构SOA中可以使用装饰者模式来组合不同的服务以创建具有复合功能的新服务。这允许服务提供者灵活地根据客户需求来定制服务
5.3 装饰者模式 VS 代理模式 代理模式可以参考《瑞_23种设计模式_代理模式》 相同点 都要实现与目标类相同的业务接口在两个类中都要声明目标对象都可以在不修改目标类的前提下增强目标方法 不同点 目的不同 装饰者是为了增强目标对象 静态代理是为了保护和隐藏目标对象获取目标对象构建的地方不同 装饰者是由外界传递进来可以通过构造方法传递 静态代理是在代理类内部创建以此来隐藏目标对象 本文是博主的粗浅理解可能存在一些错误或不完善之处如有遗漏或错误欢迎各位补充谢谢 如果觉得这篇文章对您有所帮助的话请动动小手点波关注你的点赞收藏⭐️转发评论都是对博主最好的支持~