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

    参考:

    https://www.cnblogs.com/yanggb/p/10952843.html

    https://www.cnblogs.com/xiaolovewei/p/7751332.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的一个被代理的对象,不是调用者传入的。调用者不知道你找了其他人,他也不关心这些事,只要你把事情做对了即可。

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

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

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

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

    总结

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

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

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

    转载自:http://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html

    学习AOP时,教材上面都说使用的是动态代理,可是在印象中代理模式一直都是控制访问什么的,怎么又动态增加行为了,动态增加行为不是装饰器模式吗?于是 找了很多资料,想弄清楚这两者之间到底有什么区别。结果发现这一篇英文文章讲的很清晰,就翻译一下,供参考。       

            首先,让我们先看一下下面的这两个UML类图,他们分别描述了装饰器模式和代理模式的基本实现。

                        

                         

            这两个图可能使我们产生困惑。这两个设计模式看起来很像。对装饰器模式来说,装饰者(decorator)和被装饰者(decoratee)都实现同一个 接口。对代理模式来说,代理类(proxy class)和真实处理的类(real class)都实现同一个接口。此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

            然而,实际上,在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

            我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。    

    代理模式:

    复制代码
    复制代码
    //代理模式
    public class Proxy implements Subject{

    private Subject subject;
    public Proxy(){
    //关系在编译时确定
    subject = new RealSubject();
    }
    public void doAction(){
    ….
    subject.doAction();
    ….
    }
    }
    复制代码
    复制代码
    复制代码
    复制代码
    //代理的客户
    public class Client{
    public static void main(String[] args){
    //客户不知道代理委托了另一个对象
    Subject subject = new Proxy();

    }
    }
    复制代码
    复制代码

    装饰模式:

    复制代码
    复制代码
    //装饰器模式
    public class Decorator implements Component{
    private Component component;
    public Decorator(Component component){
    this.component = component
    }
    public void operation(){
    ….
    component.operation();
    ….
    }
    }
    复制代码
    复制代码
    复制代码
    复制代码
    //装饰器的客户
    public class Client{
    public static void main(String[] args){
    //客户指定了装饰者需要装饰的是哪一个类
    Component component = new Decorator(new ConcreteComponent());

    }
    }
    复制代码

     

  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    网页设计中颜色的搭配
    CSS HACK:全面兼容IE6/IE7/IE8/FF的CSS HACK
    UVa 1326 Jurassic Remains
    UVa 10340 All in All
    UVa 673 Parentheses Balance
    UVa 442 Matrix Chain Multiplication
    UVa 10970 Big Chocolate
    UVa 679 Dropping Balls
    UVa 133 The Dole Queue
  • 原文地址:https://www.cnblogs.com/xuwc/p/14022327.html
Copyright © 2011-2022 走看看