zoukankan      html  css  js  c++  java
  • 装饰器模式和代理模式的区别

    转载自:https://www.cnblogs.com/yanggb/p/10952843.html

    装饰器模式和代理模式的区别

     

    代理模式和装饰器模式很像,这里用【到咖啡馆喝咖啡】作例子来讲解。

    基础实现

    定义一个咖啡的接口。

    复制代码
    public interface Coffee {
        /**
         * 打印当前咖啡里有什么
         */
        void printMaterial();
    }
    复制代码

    定义一个苦咖啡的实现。

    复制代码
    public class BitterCoffee implements Coffee {
        @Override
        public void printMaterial() {
            System.out.println("咖啡");
        }
    }
    复制代码

    定义一个默认的点咖啡逻辑。

    @Test
    public void orderCoffee {
        Coffee coffee = new BitterCoffee();
        coffee.printMaterial(); // 咖啡
    }

    装饰器模式

    你喝了一口咖啡,觉得有点苦,于是你就想加点糖。

    定义一个咖啡装饰器(加糖)。

    复制代码
    public class CoffeeDecorator implements Coffee {
        /**
         * 持有一个咖啡对象
         */
        private final Coffee coffee;
    
        public CoffeeDecorator(Coffee coffee) {
            this.coffee = coffee;
        }
    
        @Override
        public void printMaterial() {
            System.out.println("糖");
            this.coffee.printMaterial();
        }
    }
    复制代码

    定义一个咖啡加糖的应用逻辑。

    复制代码
    @Test
    public void addSugerIntoCoffee {
        Coffee coffee = new BitterCoffee(); // 点了一杯苦咖啡
        coffee = new SugarDecorator(coffee); // 给咖啡加了点糖
        coffee.printMaterial(); // 糖 咖啡
    }
    复制代码

    装饰器适用场景:我有一个对象,但是这个对象的功能不能使我满意(咖啡太苦了),我就拿装饰器给他装饰一下(给咖啡加糖)。

    代理模式(静态代理)

    约好的朋友来了,要给她点一杯咖啡,你知道咖啡很苦,决定直接点一杯加了糖的咖啡给她。

    定义一个加糖咖啡的类。

    复制代码
    public class CoffeeProxy implements Coffee {
        private final Coffee coffee;
    
        public CoffeeProxy() {
            this.coffee = new BitterCoffee();
        }
    
        @Override
        public void printMaterial() {
            System.out.println("糖");
            this.coffee.printMaterial();
        }
    }
    复制代码

    然后定义一个点加糖咖啡的逻辑。

    @Test
    public void addSugerIntoCoffee {
        Coffee coffee = new CoffeeProxy();
        coffee.printMaterial(); // 糖 咖啡
    }

    装饰器和代理模式的区别

    对装饰器模式来说,装饰者(Decorator)和被装饰者(Decoratee)都实现一个接口。对代理模式来说,代理类(Proxy Class)和真实处理的类(Real Class)都实现同一个接口。此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

    在上面的例子中,装饰器模式是使用的调用者从外部传入的被装饰对象(coffee),调用者只想要你把他给你的对象装饰(加强)一下。而代理模式使用的是代理对象在自己的构造方法里面new的一个被代理的对象(此处不一样通过new,聚合的方式有三种,构造、setter、接口注入(设计原则之依赖倒转)),不是调用者传入的。调用者不知道你找了其他人,他也不关心这些事,只要你把事情做对了即可。

    装饰器模式关注于在一个对象上动态地添加方法,而代理模式关注于控制对对象的访问。换句话说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例;当使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰器的构造器。

    装饰器模式和代理模式的使用场景不一样,比如IO流使用的是装饰者模式,可以层层增加功能。而代理模式则一般是用于增加特殊的功能(代理模式更倾向于功能隐藏),有些动态代理不支持多层嵌套。

    代理和装饰其实从另一个角度更容易去理解两个模式的区别:代理更多的是强调对对象的访问控制,比如说,访问A对象的查询功能时,访问B对象的更新功能时,访问C对象的删除功能时,都需要判断对象是否登陆,那么我需要将判断用户是否登陆的功能抽提出来,并对A对象、B对象和C对象进行代理,使访问它们时都需要去判断用户是否登陆,简单地说就是将某个控制访问权限应用到多个对象上;而装饰器更多的强调给对象加强功能,比如说要给只会唱歌的A对象添加跳舞功能,添加说唱功能等,简单地说就是将多个功能附加在一个对象上。

    所以,代理模式注重的是对对象的某一功能的流程把控和辅助,它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。而装饰模式注重的是对对象功能的扩展,不关心外界如何调用,只注重对对象功能加强,装饰后还是对象本身。

    总结

    对于代理类,如何调用对象的某一功能是思考重点,而不需要兼顾对象的所有功能;对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其他功能,因为再怎么装饰,本质也是对象本身(体现的是功能增强,原始功能基本不变),要担负起对象应有的职责,被装饰者的职责一旦增加,作为装饰类也需要有相应的扩展,必然会造成编码的负担。

    设计模式本身是为了提升代码的可扩展性,灵活应用即可,不必生搬硬套,非要分出个所以然来,装饰器模式和代理模式的区别也是如此。

  • 相关阅读:
    ASP字符串16进制互转
    LINQ Dictionary加速查询(TryGetValue)
    ASP中将UTF8格式的URL进行解码。函数
    C# 保护进程不被结束(源代码)防任务管理器结束进程
    用WebBrowser做web 打印时的权限不足。。。。
    .net 2.0 中 ‘注册为 allowDefinition='MachineToApplication' 的节是错误的’
    sql 2005 中分页
    BitComet web 插件和 flash get web 插件 对脚本的影响
    同时使用 C# and VB.NET 在 .net 2.0 中
    用触发器实现主从表关系(主表更改从表更改 )
  • 原文地址:https://www.cnblogs.com/yangmin86/p/13718646.html
Copyright © 2011-2022 走看看