装饰者模式与代理模式

装饰者模式

  • 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

  • 优点:

    • 采用组合的方式,可以动态的扩展功能,同时也可以在运行时选择不同的装饰器,来实现不同的功能。
    • 被装饰者与装饰者解偶,被装饰者可以不知道装饰者的存在,同时新增功能时原有代码也无需改变,符合开放封闭原则。
    • 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
  • 缺点:

    • 装饰层过多的话,维护起来比较困难。
    • 如果要修改抽象组件这个基类的话,后面的一些子类可能也需跟着修改,较容易出错。
  • 角色说明

    • ITarget: 接口或者抽象类,被装饰的最原始的对象。具体组件与抽象装饰角色的父类。
    • TargetImpl: 实现抽象组件的接口。
    • Decorator: 一般是抽象类,抽象组件的子类,同时持有一个被装饰者的引用,用来调用被装饰者的方法;同时可以给被装饰者增加新的职责。
    • DecoratorSub: (具体装饰类):抽象装饰角色的具体实现。
  • 类图如下:

    装饰者模式与代理模式_第1张图片

  • 代码实现如下:

    
    interface ITarget {
        fun operation(): String
    }
    
    class TargetImpl : ITarget {
        override fun operation(): String {
            return "我是歌手"
        }
    }
    
    abstract class Decorator(private val target: ITarget) : ITarget {
        override fun operation(): String {
            return target.operation()
        }
    }
    
    class DecoratorSub(target: ITarget) : Decorator(target) {
        override fun operation(): String {
            return addSome(super.operation())
        }
    
        private fun addSome(origin: String): String {
            return "$origin,但是我也学会了表演"
        }
    }
    
    fun main(args: Array) {
        val target = TargetImpl()
        val decorator = DecoratorSub(target)
        decorator.operation()
    }
    

静态代理

  • 静态代理与装饰者模式很像,但是目的不一样,代理的目的是控制对对象的访问,不会对对象的内容做修改
    而装饰者模式的目的是增强对象的功能。

  • 类图如下:
    装饰者模式与代理模式_第2张图片

  • 代码实现如下:

    
    interface ITarget {
        fun operation(cost: Int)
    }
    
    class TargetImpl(val name: String) : ITarget {
    
        override fun operation(cost: Int) {
            println("$name 参加xx活动演唱,出场费:$cost 元")
        }
    }
    
    class Proxy(private val targetImpl: TargetImpl) : ITarget {
        override fun operation(cost: Int) {
            if (preOption(cost)) {
                targetImpl.operation(cost)
            } else {
                println("老子不差你这点钱")
            }
        }
    
        private fun preOption(cost: Int): Boolean {
            return cost > 100000
        }
    
    }
    
    fun main(args: Array) {
        val aa = TargetImpl("S")
        val agent = Proxy(aa)
        agent.operation(100)
        agent.operation(10000000)
    }
    
  • 装饰者模式和静态代理模式在实现上很像,但是两者的目的不同,所以在代理类和装饰者类中的实现上有着不同的处理。

动态代理

简介

  • 不需要显式实现与目标对象类相同的接口,而是将这种实现推迟到程序运行时由 JVM来实现
  • 通过Java 反射机制的method.invoke(),通过调用动态代理类对象方法,从而自动调用目标对象的方法
  • 优点:
    • 只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码,更强的灵活性
    • 在使用时(调用目标对象方法时)才会动态创建动态代理类 & 实例,不需要事先实例化。
  • 缺点:
    • 效率低,相比静态代理中 直接调用目标对象方法,动态代理则需要先通过Java反射机制 从而 间接调用目标对象方法
    • 应用场景局限,因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口 创建 代理类,不能针对类 创建代理类
  • 应用领域
    • 基于静态代理应用场景下,需要代理对象数量较多的情况下使用动态代理
    • AOP 领域,Aspect Oriented Programming 面向切面编程,是OOP的延续、函数式编程的一种衍生范型,
      作用:通过预编译方式和运行期动态代理实现程序功能的统一维护。优点:降低业务逻辑各部分之间的耦合度 、 提高程序的可重用性 & 提高了开发的效率
      具体应用场景:日志记录、性能统计、安全控制、异常处理等。

动态代理实现

  • 使用java中的InvocationHandler实现
    • 类图如下:
      装饰者模式与代理模式_第3张图片
    • 创建动态代理类实现InvocationHandler接口
        public class DynamicProxy implements InvocationHandler {
        // 声明代理对象
        private T proxyObject;
    
        public T newProxyInstance(T proxyObject) {
            this.proxyObject = proxyObject;
            return (T) Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(), proxyObject
                    .getClass().getInterfaces(), this);
        }
    
        /**
         * 动态代理对象调用目标对象的任何方法前,都会调用调用处理器类的invoke
         *
         * @param proxy  动态代理对象(即哪个动态代理对象调用了method()
         * @param method 目标对象被调用的方法
         * @param args   指定被调用方法的参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            preOperation();
            Object result = method.invoke(proxyObject, args);
            postOperation();
            return result;
        }
    
        private void preOperation() {
            System.out.println("开始调用");
        }
    
        private void postOperation() {
            System.out.println("调用结束");
        }
    }
    
    
    • 创建需要代理的类
        public interface Person {
        void say();
    }
    
        public class Asian implements Person {
        @Override
        public void say() {
            System.out.println("黄种人");
        }
    }
    
    
    • 使用
       public class Main {
        public static void main(String[] args) {
            Asian person = new Asian();
            DynamicProxy dynamicProxy = new DynamicProxy();
            dynamicProxy.newProxyInstance(person).say();
        }
    }
    

你可能感兴趣的:(设计模式,Kotlin,for,Android)