【设计模式深度剖析】【1】【结构型】【代理模式】| 玩游戏打怪、升级为例加深理解

👈️上一篇:创建型设计模式对比 | 下一篇:装饰器模式👉️

目 录

代理模式

定义

英文原话

Provide a surrogate or placeholder for another object to control access to it.

直译

为另一个对象提供代理或占位符以控制对它的访问

如何理解?

字面上不好理解的话可以结合代码进一步理解下,从具体实现上分析:

抽象主题角色,是对被代理类的抽象,被代理类就看作是对抽象主题角色类的实现,被代理类的实现就是核心功能的实现

同时,代理对象中持有被代理对象的引用,

代理类也实现了被代理类相同的接口,

这样,通过代理类可以增强被代理类的逻辑,

在被代理对象的逻辑前后可以增加一些逻辑,比如获取请求参数,添加日志等,这些非核心的逻辑,可以在代理类中进行增强。

代理模式应用非常广泛,大到一个系统框架、企业平台,小到事务处理、代码片段,随处可见代理模式的使用,例如,Java RMI的远程调用就是一种代理模式的应用,AOP也可以通过代理模式实现。

3个角色

UML类图

1. 抽象主题(Subject)角色

该角色是真实主题和代理主题的共同接口,以便在任何可以使用真实主题的地方都可以使用代理主题。

2. 代理类:代理主题(Proxy Subject)角色

也叫做委托类、代理类,该角色负责控制对真实主题的引用,负责在需要的时候创建或删除真实主题对象,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

3. 被代理类:真实主题(Real Subject)角色

该角色也叫做被委托角色、被代理角色,是业务逻辑的具体执行者。

代码示例

1. 真实主题,被代理类

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;

public class Target implements AbstractSubject {

    @Override
    public void m1() {
        System.out.println("target implements. Core business logic");
    }
}

2. 抽象主题

抽取核心业务逻辑接口方法m1()出来,该方法源自被代理对象,因此被代理类的m1()方法就可以看作是对它的实现,被代理类添加 implements AbstractSubject表示对抽象主题的实现;

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;

public interface AbstractSubject {
    void m1();
}

3. 代理类

代理被代理的类,对被代理类的逻辑(抽象主题进行了抽象)进行增强,

前提是代理类实现了抽象主题的抽象方法,同时持有被代理类的对象(可通过构造函数传入)

注意 这里的构造函数传入的是Target实例,更通用的可以使用抽象主题角色AbstractSubject类型;

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;

public class Proxy implements AbstractSubject {

    private Target target;

    public Proxy(Target target) {
        this.target = target;
    }

    @Override
    public void m1() {
        before();
        target.m1();
        after();
    }

    private void before() {
        System.out.println("enhanced logic: before...");
    }

    private void after() {
        System.out.println("enhanced logic: after...");
    }
}

4. 测试类

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;

public class DemoTest {
    public static void main(String[] args) {
        Target target = new Target();
        Proxy proxy = new Proxy(target);
        proxy.m1();
    }
}

/* Output:
enhanced logic: before...
target implements. Core business logic
enhanced logic: after...
*///~

代理模式的种类

简单了解一下:

  1. 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局部代表对象。这个不同的地址空间可以是在本机器中,也可以在另一台机器中。
  2. 虚拟(Virtual**)**代理:有时需要创建一些消耗较多资源的对象,可以首先创建代理对象,而将真实对象的创建延迟。例如,加载一个很大的图片,可以通过图片的代理来代替真正的图片。
  3. 保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
  4. 缓存(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  5. 同步(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
  6. 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,例如,记录访问的流量和次数等。

代理模式的优点

  1. 职责清晰真实的角色实现实际的业务逻辑,不用关心其他非本职的事务,通过后期的代理完成附加的事务,附带的结果就是编程简洁清晰。
  2. 高扩展性 :具体主题角色随需求不同可能有很多种,但只要实现了接口,代理类完全可以不做任何修改的情况下代理各种真实主题角色
  3. 智能化:代理类可以在运行时才确定需要去代理的真实主题,这是一种强大的功能。

示例解析:玩游戏打怪、升级示例

UML类图

  • 主题类和代理类同时实现接口
  • 主题类,就是被代理类,完成主要业务逻辑
  • 附加业务在代理类中完成
  • 客户端调用:
    • 声明接口的两个示例分别指向主题类与代理类的实例对象;
    • 其中,在代理类示例创建时传入主题类的实例(参数类型可以放大,参数定义为接口类型,当然主题类实现类此接口,属于此接口类型,可以被传入)。

1. 真实主题RealSubject:GamePlayer实现IGamePlayer接口中的方法

被代理类的具体实现,是最核心的业务逻辑,这里玩游戏最核心的就是打怪,升级;

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy;

public class GamePlayer implements IGamePlayer {
    private String name = "";

    public GamePlayer(String name) {
        this.name = name;
    }

    @Override
    public void killBoss() {
        System.out.println(this.name + "在打怪!");
    }

    @Override
    public void upGrade() {
        System.out.println(this.name + "成功升了1级!");
    }
}

抽象主题Subject:IGamePlayer接口对游戏玩家进行抽象

抽象主题,抽象出打怪升级两个核心业务逻辑,方便代理类进行实现,增强被代理类的逻辑

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy;

public interface IGamePlayer {
    //杀怪
    void killBoss();
    //升级
    void upGrade();
}

代理主题ProxySubject:GamePlayerProxy是代理类

代理主题,在被代理类的核心业务逻辑实现(打怪、升级)的基础上++增加非核心业务逻辑:加日志、计时,++

因此代理类是对被代理类的增强、强化

他持有被代理类的引用,通过构造函数初始化

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy;

import java.util.Date;

public class GamePlayerProxy implements IGamePlayer {

    private IGamePlayer player = null;

    public GamePlayerProxy(IGamePlayer player) {
        this.player = player;
    }

    //记录打怪的时间
    private void log() {
        System.out.println("打怪时间 " + new Date().toString());
    }

    @Override
    public void killBoss() {
        this.log();
        player.killBoss();
    }

    @Override
    public void upGrade() {
        player.upGrade();
        this.countTime();
    }

    //计时
    private void countTime() {
        System.out.println("升1级耗时50小时");
    }

}

测试类

java 复制代码
package com.polaris.designpattern.list2.structural.pattern1.proxy;

public class DemoTest {
    public static void main(String[] args) {
        IGamePlayer player = new GamePlayer("李逍遥");
        IGamePlayer proxy = new GamePlayerProxy(player);
        proxy.killBoss();
        proxy.upGrade();
    }
}

/* Output:
打怪时间 Mon May 20 23:35:58 CST 2024
李逍遥在打怪!
李逍遥成功升了1级!
升1级耗时50小时
*///~

👈️上一篇:创建型设计模式对比 | 下一篇:装饰器模式👉️

相关推荐
为将者,自当识天晓地。13 分钟前
c++多线程
java·开发语言
daqinzl21 分钟前
java获取机器ip、mac
java·mac·ip
激流丶36 分钟前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue40 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
让学习成为一种生活方式1 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
晨曦_子画1 小时前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
Heavydrink2 小时前
HTTP动词与状态码
java
ktkiko112 小时前
Java中的远程方法调用——RPC详解
java·开发语言·rpc
计算机-秋大田2 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue