• 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()+"	月资费是:"+order.price());
    
            BuyOrder00 order1 = new BuyOrderTalk(order);
            System.out.println(order1.getOrder()+"	月资费是:"+order1.price());
    
            BuyOrder00 order2 = new BuyOrderNet(order);
            System.out.println(order2.getOrder()+"	月资费是:"+order2.price());
    
            BuyOrder00 order3 = new BuyOrderMSG(order);
            System.out.println(order3.getOrder()+"	月资费是:"+order3.price());
    
            BuyOrder00 order4 = new BuyOrderMSG(order2);
            System.out.println(order4.getOrder()+"	月资费是:"+order4.price());
    
            BuyOrder00 order5 = new BuyOrderMSG(order1);
            System.out.println(order5.getOrder()+"	月资费是:"+order5.price());
    
            BuyOrder00 order6 = new BuyOrderNet(order1);
            System.out.println(order6.getOrder()+"	月资费是:"+order6.price());
    
            BuyOrder00 order7 = new BuyOrderNet(new BuyOrderMSG(new BuyOrderTalk(order)));
            System.out.println(order7.getOrder()+"	月资费是:"+order7.price());
            
        }
    
    }

     运行结果

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

  • 相关阅读:
    小白的基金理财课
    Spring Security 入门原理及实战
    spring-data-rest的魔力 10分钟实现增删改查
    redis单点、redis主从、redis哨兵sentinel,redis集群cluster配置搭建与使用
    Netty开发redis客户端,Netty发送redis命令,netty解析redis消息
    使用Netty实现HTTP服务器
    Netty实现心跳机制
    SpringMVC是怎么工作的,SpringMVC的工作原理
    Netty 学习系列
    Mybatis 源码学习系列
  • 原文地址:https://www.cnblogs.com/kuoAT/p/6951706.html
Copyright © 2020-2023  润新知