デコレータモードとエージェンシーモード

デコレータモード

  • オブジェクトにいくつかの追加の責任を動的に追加します。関数を増やすという点では、装飾モードはサブクラスを生成するよりも柔軟性があります。

  • 利点:

    • 組み合わせ方法を使用すると、機能を動的に拡張でき、実行時にさまざまなデコレータを選択してさまざまな機能を実現できます。
    • デコレータとデコレータは分離されており、デコレータはデコレータの存在を知る必要がありません。同時に、関数を追加するときに元のコードを変更する必要がなく、オープンとクローズの原則に準拠しています。
    • これは、オブジェクト関数を拡張するための継承の使用によって引き起こされる、柔軟性の低さやサブクラスの無制限の拡張の問題を効果的に回避します。
  • 短所:

    • 装飾層が多すぎると、メンテナンスが難しくなります。
    • 抽象コンポーネントの基本クラスを変更する場合は、後続のサブクラスも変更する必要があり、エラーが発生しやすくなります。
  • 役割の説明

    • ITarget:インターフェイスまたは抽象クラス。装飾される最もプリミティブなオブジェクト。具体的なコンポーネントと抽象的な装飾的な役割の親クラス。
    • TargetImpl:抽象コンポーネントのインターフェースを実装します。
    • デコレータ:これは通常、抽象クラス、抽象コンポーネントのサブクラスであり、デコレータのメソッドを呼び出すためのデコレータへの参照も保持します。同時に、デコレータに新しい責任を追加できます。
    • DecoratorSub :(具体的な装飾クラス):抽象的な装飾の役割の具体的な実現。
  • クラス図は次のとおりです。

    ここに画像の説明を挿入

  • コードは次のように実装されています。

    
    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<String>) {
        val target = TargetImpl()
        val decorator = DecoratorSub(target)
        decorator.operation()
    }
    

静的プロキシ

  • 静的プロキシはデコレータモードと非常に似ていますが、目的が異なります。プロキシの目的は、オブジェクトのコンテンツを変更せずにオブジェクトへのアクセスを制御
    することですが、デコレータモードの目的は、機能を強化することです。オブジェクトの。

  • クラス図は次のとおりです。
    ここに画像の説明を挿入

  • コードは次のように実装されています。

    
    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<String>) {
        val aa = TargetImpl("S")
        val agent = Proxy(aa)
        agent.operation(100)
        agent.operation(10000000)
    }
    
  • デコレータパターンと静的プロキシパターンの実装は非常に似ていますが、2つの目的が異なるため、プロキシクラスとデコレータクラスの実装には異なる処理があります。

動的プロキシ

前書き

  • ターゲットオブジェクトクラスと同じインターフェイスを明示的に実装する必要はありませんが、プログラムがJVMによって実行されるまでこの実装を延期します。
  • Javaリフレクションメカニズムのmethod.invoke()を介して、動的プロキシクラスオブジェクトのメソッドを呼び出すことにより、ターゲットオブジェクトのメソッドが自動的に呼び出されます。
  • 利点:
    • 1つの動的プロキシクラスだけが、複数の静的プロキシを作成する問題を解決し、重複や冗長なコードを回避し、柔軟性を高めることができます。
    • 動的プロキシクラスとインスタンスは、使用時に(ターゲットオブジェクトメソッドが呼び出されたときに)動的に作成され、事前のインスタンス化は必要ありません。
  • 短所:
    • 効率が低い。静的プロキシでのターゲットオブジェクトメソッドの直接呼び出しと比較して、動的プロキシは、Javaリフレクションメカニズムを介してターゲットオブジェクトメソッドを間接的に呼び出す必要があります。
    • Javaの単一の継承機能(各プロキシクラスはプロキシクラスを継承する)のため、アプリケーションシナリオは制限されます。つまり、プロキシクラスはインターフェイスに対してのみ作成でき、プロキシクラスはクラスに対して作成できません。
  • 応用分野
    • 静的プロキシアプリケーションのシナリオに基づいて、動的プロキシは、多数のプロキシオブジェクトが必要な場合に使用されます
    • AOPの分野では、アスペクト指向プログラミングはOOPの継続であり、関数型プログラミングの派生パラダイムであり、その
      役割は、プリコンパイルとランタイム動的エージェントを通じてプログラム機能の統一された保守を実現することです。利点:ビジネスロジックのさまざまな部分間の結合を減らし、プログラムの再利用性を向上させ、開発の効率を高め
      ます特定のアプリケーションシナリオ:ロギング、パフォーマンス統計、セキュリティ制御、例外処理など。

動的プロキシの実装

  • JavaでInvocationHandlerを使用して
    • クラス図は次のとおりです。
      ここに画像の説明を挿入
    • 動的プロキシクラスを作成して、InvocationHandlerインターフェイスを実装します
        public class DynamicProxy<T extends Person> 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();
        }
    }
    

おすすめ

転載: blog.csdn.net/genmenu/article/details/88876483