Javaデザインパターンのエージェントモード(7)

意のままに気性を失わないでください。人生において、人が知っているすべての人と友達になることは不可能です。真の友人を強制することはできず、神は誰が誰と友人でなければならないかを規定していません。すべてがやりたがらない必要があります。人生のすべてが嫌がる可能性があります。「愛」だけが嫌がることはできません。友情は同じです。

デザインパターンの学習、近い将来23のデザインパターンについてブログを書きますので、お楽しみに〜
—1 / 9/2021

定義

このオブジェクトへのアクセスを制御するために、他のオブジェクトのプロキシを提供します。場合によっては、オブジェクトが適切でないか、別のオブジェクトを直接参照できず、プロキシオブジェクトがクライアントとターゲットオブジェクトの間の仲介役を演じることがあります。

Baidu百科事典

役割の分類

  • 抽象ロール:実際のロールを宣言するインターフェースまたは抽象クラスによって実装されるビジネスメソッド。
  • エージェントロール:実ロールのエージェントである抽象ロールを実現します。抽象メソッドは実ロールのビジネスロジック方式で実現し、独自のオペレーションを付加することができます。
  • 実際の役割:抽象的な役割を実装し、エージェントの役割が呼び出すために、実際の役割によって実装されるビジネスロジックを定義します

分析

家を借りたいとしたら、まず代理店に行って家を見てから、借りるのに適した家を選ぶ必要があります。

家はどこから来たの?家主に違いないですよね?

ここでは、家主はエージェントが必要な人で、エージェントは家です。家のエージェントをエージェントにして、エージェントに貸し出してもらいましょう。

利点:

  • 家主は何も変わっていませんが、家は代理人が代理を務めており、家を借りた後、代理人が家を借りて、代理人手数料などを請求します。

UML类图(1.1)


分析:

  • HouseMasterの本当の役割は、ここで家主を指します
  • IHouseの抽象的な役割はここの家を指します
  • ここでのHouseProxyエージェントの役割は仲介者を指します

静的プロキシの実装:

IHouse(家):

public interface IHouse {
    
    
    void showHouse();
}

HouseMaster(ホスト):

public class HouseMaster implements IHouse {
    
    

    @Override
    public void showHouse() {
    
    
        Log.i("代理模式:", "我是房东,我要出租房");
    }
}

HouseProxy(中間):

public class HouseProxy {
    
    

    IHouse house;
    //吧房子交给中介 (吧IHouse 接口组合到 HouseProxy 上)
    public HouseProxy( IHouse house) {
    
    
        this.house = house;
    }

    public void showHouse(){
    
    
        house.showHouse();//房东的房子
    }

}

使用コード:

//创建代理类 传入需要代理的类
HouseProxy houseProxy = new HouseProxy(new HouseMaster());

houseProxy.showHouse();

Log图(2.1)


まだ誰もがエージェンシーモデルに魅了されているのかもしれませんが、詳しく説明します

現在、HouseProxy(仲介)を使用して家主Aの家を表示するだけで、他の操作も実行できます。たとえば、家主に他の家を表示させることができます。また、エージェントにチップを渡すこともできます。

HouseProxy(中間)クラス:

public class HouseProxy {
    
    

    IHouse house;
    public HouseProxy( IHouse house) {
    
    
        this.house = house;
    }

    public void showHouse(){
    
    
        money();//收取消费
        house.showHouse();//房东的房子
        seeHouse();//带用户看房
    }
    public void money(){
    
    
        Log.i("代理模式:","我是中介,我要收取消费");
    }
    public void seeHouse(){
    
    
        Log.i("代理模式:","我是中介,我带用户看房");
    }
}

Log图(2.2)


房东并没有发生变化,变化的只是中介
比如说在项目中,一个类用到了很多地方现在让这个这个类前面输出一句话,
咋们是不是就可以不在改变原有代码的基础上来达到这句话的显示呢?

静的プロキシモードの概要:

利点:

  • 元のコードに変更はなく、開始と終了の原則を満たしています(変更のために閉じられています)
  • 分業を実現するために公開コードがエージェントクラスに引き渡される
  • あなたの責任ではない他の事柄を気にせず、後のエージェントを通じて完了したトランザクションを完了します。偶発的な結果として、プログラミングは単純で明確になります。

短所:

  • 1つのクラスでプロキシクラスを作成する必要があり、コードの量が2倍になり、開発効率が低下します

動的プロキシモード

動的プロキシとは、プロキシの変更

に応じてプロキシクラスを変更できることを意味します。簡単に言えば、多くのプロキシクラスを作成せずに、Aをプロキシするだけで、BをBにプロキシする必要があります。

役割:

  • InvocationHandler呼び出しハンドラ
  • プロキシ

InvocationHandlerとは何ですか?

JDK1.8CHW图(3.1)


JDK1.8CHWダウンロード抽出コード:lfoz

InvocationHandlerは、プロキシインスタンスの呼び出しハンドラーによって実装されるインターフェイスです。


InvocationHandlerは、
invoke(Object proxy、Method method、Object [] args)メソッドに書き直す必要があるインターフェースです。

メソッドの説明を呼び出​​す:

  • パラメータ1(オブジェクトプロキシ):メソッドを呼び出すプロキシインスタンス
  • パラメータ2(メソッドメソッド):メソッドオブジェクトの宣言されたクラスは、メソッドによって宣言されたインターフェイスになり、メソッドのプロキシインターフェイスを継承するプロキシクラスのスーパーインターフェイスにすることができます。(ここで理解していなくても構いません)
  • パラメータ3(Object [] args):プロキシインスタンスのパラメータ値を渡すメソッド呼び出しを含むオブジェクトの配列。インターフェイスメソッドにパラメータがない場合はnull。プリミティブ型のパラメーターは、java.lang.Integerやjava.lang.Booleanなどの適切なプリミティブラッパークラスのインスタンスに含まれています。

これはjdkでの説明です。ここでのメソッドの説明が明確でなくてもかまいません。

JDK1.8CHW图(3.2)

プロキシとは何ですか?

JDK1.8CHW图(3.3)


Proxyは、動的プロキシクラスとインスタンスを作成するための静的メソッドを提供します。これは、これらのメソッドによって作成されるすべての動的プロキシクラスのスーパークラスでもあります。(公式の言葉)

私の理解:プロキシはプロキシのインスタンスを取得することです

それほど多くの単語を読みたくないことは間違いありません。簡単に言えば、プロキシはInvocationHandlerと連携して、プロキシクラスの自動生成を完了します。

プロキシインスタンスを取得した場合:

Proxy.newProxyInstance(
		ClassLoader loader,
        Class<?>[] interfaces,
        InvocationHandler h);

Proxy.newProxyInstanceパラメーター分析:

  • パラメータ1:ロードされたクラスの場所
  • パラメータ2:プロキシインターフェイス
  • パラメータ3:自分自身を表す:InvocationHandler

コード:

ProxyInvocationHandlerクラス:

public class ProxyInvocationHandler implements InvocationHandler {
    
    

    Object object;

    //参数一:object 具体接口的实现类
    public ProxyInvocationHandler(Object object) {
    
    
        this.object = object;
    }

    //生成代理类  返回的是被代理的接口 (返回的是object接口)
    public Object getProxy(){
    
    
        /**
         * this.getClass().getClassLoader() 加载类所在位置
         * object.getClass().getInterfaces() 代理的接口
         * this  表示本身:InvocationHandler
         */
       return Proxy.newProxyInstance(
			       this.getClass().getClassLoader(),
			       object.getClass().getInterfaces(),
			       this
	     	 );
    }

    /**
     * @param proxy 调用该方法的代理实例
     * @param method  所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
     * @param args 包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。
     *             原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
     * @return
     * @throws Throwable
     */
    @Override  //处理代理实例,返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        Object invoke = method.invoke(object, args);
        return  invoke;
    }
}

使用する:

//需要代理 真实角色
HouseMaster houseMaster = new HouseMaster();

//代理类生成器  传入需要代理的类
ProxyInvocationHandler pit =
			 new ProxyInvocationHandler(houseMaster);

//生成代理类 (必须返回接口)
IHouse proxy = (IHouse) pit.getProxy();

//输出租房子
proxy.showHouse();

Log图(2.3)


HouseMaster(プロキシクラス)は、ProxyInvocationHandler(呼び出しハンドラ)クラスのリフレクションメカニズムを介して、対応するIHouse(インターフェイス)を自動的に生成します。

注意:


InvocationHandlerのリフレクションメカニズムを使用して、現在呼び出されているメソッドを取得します。

public class ProxyInvocationHandler implements InvocationHandler {
    
    

	.....
	
    @Override  //处理代理实例,返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        msg(method.getName());
        Object invoke = method.invoke(object, args);
        return  invoke;
    }

    public void msg(String msg){
    
    
        Log.i("代理模式","代理了"+ msg +"方法");
    }
}

流程图(4.1)


取得したshowHouse()メソッドの名前は次のとおりです

Log图(2.4)

これで、このProxyInvocationHandlerはパブリックプロキシクラスになり、プロキシを必要とするクラスに渡されます。その後、プロキシクラスのオブジェクトをgetProxy()を介して返すことができます(渡されたプロキシクラスが返されたプロキシクラスを実装している場合)

利点:

  • 元のコードに変更はなく、開始と終了の原則を満たしています(変更のために閉じられています)
  • 分業を実現するために公開コードがエージェントクラスに引き渡される
  • 動的プロキシエージェントはインターフェイスであり、通常は対応するビジネスです
  • 動的プロキシは、同じインターフェイスを実装している限り、複数のインターフェイスをプロキシできます。静的プロキシと比較して、各プロキシクラスは、より柔軟なプロキシクラスを作成する必要があります。

動的コードは比較的固定されているため、この記事を本当に理解していない場合は、この記事を使用できます。

各クラスが対応する役割を果たし、使用されることを知っておいてください。

  • ProxyInvocationHandler呼び出しハンドラー(プロキシークラスを自動的に生成するために使用)

  • HouseMasterの本当の役割(代表される必要があります(この記事は家を借りる家主に言及しています))

  • IHouseの抽象的な役割(ここでは家を指します)

  • pit.getProxy()は抽象ロールを返します(ここでは家に戻ることを指します)

  • proxy.showHouse();特定の実装(家を借りることを参照)

プロジェクトを完了する

デザインパターン/デザイン原則のホームページに移動します

オリジナリティは簡単ではありません、あなたの好きなものは私にとってあなたの最大のサポートです、私をサポートしたいです〜

おすすめ

転載: blog.csdn.net/weixin_44819566/article/details/112390541