博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java设计模式之 装饰器模式
阅读量:6759 次
发布时间:2019-06-26

本文共 5915 字,大约阅读时间需要 19 分钟。

装饰器模式

装饰器模式(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());            }}

 运行结果

 

建议多打几个断点观察流程情况,一边更好的理解装饰器模式的工作流程

 

转载于:https://www.cnblogs.com/kuoAT/p/6951706.html

你可能感兴趣的文章
Windows 7 共享文件夹 给 VirtualBox 中的 Ubuntu 14
查看>>
iOS开发UI篇—字典转模型
查看>>
Web接口测试工具--Jmeter
查看>>
[LeetCode] Remove K Digits 去掉K位数字
查看>>
spring profile 多环境配置管理
查看>>
iOS开发 iOS10推送必看
查看>>
C#设计模式——抽象工厂模式(Abstract Factory Pattern)
查看>>
软件测试--关键字
查看>>
nginx知识点
查看>>
字符串操作(字符数统计及字符串反转)
查看>>
递归写法参考
查看>>
【Python】学习笔记八:面向对象
查看>>
单片机中PWM的原理与控制程序
查看>>
RStudio中,出现中文乱码问题的解决方案
查看>>
【SQL 触发器】
查看>>
Kafka server部署配置优化
查看>>
(转) Artificial intelligence, revealed
查看>>
【转】VS项目属性的一些配置项的总结
查看>>
Project、Target、Workspace and Scheme
查看>>
topas top vmstat
查看>>