从王者荣耀看设计模式(保护代理模式)

从王者荣耀看设计模式(保护模式)

一.简介

打开王者荣耀,点击右上角头像标志可进入我的信息主页。在我的个人主页中,我可以可设置玩家的游戏昵称,性别,常用英雄。除此之外,我还可以查看自己得到别人点赞的次数(不能给自己点赞);其他玩家亦可访问我的主页,可以给我点赞,可以查看我设置的所有信息(不能更改)。

二.保护代理(控制用户的访问权限)

保护代理,是提供某些级别的保护,根据客户的权限和决定客户可否访问哪些特定的方法,所以保护代理可能只提供给客户部分接口。

三.Java动态代理

Java在java.lang.reflect包中有自己的代理支持,利用这个包可以在运行时动态地创建一个代理类,实现一个或多个接口。并将方法的调用转发到你所指定的类。因为实际的代理类是在运行时创建的,我们称这个Java技术为:动态代理
(

动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
java的反射机制
我们需要利用Java的反射机制实现动态代理来创建保护代理。但在这之前,让我们先看一下类图,了解一下动态代理。

因为Java已经为我们创建了Proxy类,所以只需要有方法来告诉Proxy类要做什么。不能像以前一样把代码放进Proxy类中,以为Proxy不是我们直接实现的。既然代码不能放到Proxy类中,那么需要放到哪里?放在InvocationHandler中,InvocationHandler的工作是响应代理的任何调用。可以把InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法

Object invoke(Object proxy,Method method,Object[] args) throws Throwable
@param proxy:指代我们所代理的那个真实对象
@param method:指代的是我们所要调用真实对象的某个方法的Method对象
@param args:指代的是调用真实对象某个方法时接收的参数。

(^_?)☆o(′^`)oo(╥﹏╥)oヽ(ー_ー)ノ(??へ??╬)ψ(*`ー′)ψ!!!∑(?Д?ノ)ノ|??ω?` )

在让我们看看Proxy这个类:

Proxy provides static methods for creating dynamic proxy classes and instances, and is also the superclass of all dynamic proxy classes created by those methods.
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多方法,但是我们用的最多的就是newProxyInstance这个方法:
public static Object newProxyInstance(ClassLoader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
这个方法的作用就是得到一个动态的代理对象,其接收三个参数,让我们来看看这三个参数所代表的意义:
public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException
@param loader:一个ClassLoader对象,定义了那个ClassLoader对象来对生成的代理对象进行加载
@param interface:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么借口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用遮住接口中的方法了。**我们给代理对象提供了一组什么借口,那么我这个代理对象就会实现这组接口)
@param h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

四.结构图

五.设计类图

六.代码实现

步骤一:编写通用方法接口以及接口实现
保护代理模式目标是实现对访问类的控制
PersonBean类(主题接口)

package com.practice.Player;
/*
 * 这个接口可以设置和取得人的名字、性别、常用英雄和赞数量
 */
public interface PersonBean {
    String getPlayerID();
    String getGender();
    String getCommonHero();
    int getYesNumber();

    void setPlayerID(String PlayerID);
    void setGender(String gender);
    void setCommonHero(String CommonHero);
    void setYesNumber();
    void setAllCount(int Count);
}

PersonBeanImpl类(主题类)

package com.practice.Person.Impl;

import com.practice.Player.PersonBean;

public class PersonBeanImpl implements PersonBean {
    String playerID;
    String gender;
    String CommonHero;
    int yesAllCount;

    public String getPlayerID() {
        return playerID;
    }

    public String getGender() {
        return gender;
    }

    public String getCommonHero() {
        return CommonHero;
    }

    public int getYesNumber() {
        return yesAllCount;
    }

    public void setPlayerID(String playerID) {
        this.playerID = playerID;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setCommonHero(String CommonHero) {
        this.CommonHero = CommonHero;
    }

    public void setYesNumber() {
        yesAllCount++;
    }

    public void setAllCount(int Count) {
        this.yesAllCount = Count;
    }
}

步骤二:创建两个InvocationHandler
InvocationHandler实现了代理的行为,Java负责创建真实代理类和对象。我们只需提供在方法调用发生时知道做什么的handler。我们需要写两个InvocationHandler(调用处理器),其中OwnerHandler类给调用者使用.NonOwnerHandler给非拥有者使用。InvocationHandler::当代理方法被调用时,代理就会把这个调用转发给InvocaionHandler,但是这并不是通过调用InvocationHandler的对应方法做到的。而是给拥有者使用的OwnerHandler类

OwnerInvacationHandler类(给拥有者使用)

package com.practice.Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.practice.Player.PersonBean;

public class OwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public OwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException{
        try {
            if(method.getName().startsWith("get")) {
                return method.invoke(person, args);
            }else if(method.getName().equals("setYesNumber")) {
                throw new IllegalAccessException();
            }else if(method.getName().startsWith("set")) {
                return method.invoke(person, args);
            }
        }catch(InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

}

NonOwnerInvocationHandler类(给非拥有者使用)

package com.practice.Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.practice.Player.PersonBean;

public class NonOwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public NonOwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException{
        try {
            if(method.getName().startsWith("get")) {
                return method.invoke(person, args);
            }else if(method.getName().equals("setYesNumber")){
                return method.invoke(person, args);
            }else if(method.getName().startsWith("set")) {
                throw new IllegalAccessException();
            }
        }catch(InvocationTargetException e) {
            e.printStackTrace();
        }
        // TODO Auto-generated method stub
        return null;
    }

}

步骤三. 创建Proxy类并实例化Proxy对象
开始编写一个以PersonBean为参数,并知道如何为PersonBean对象创建拥有者代理的方法,也就是说,我们要创建一个代理,将它的方法调用转发给OwnerInvocationHandler

获取拥有者方法代理

    PersonBean getOwnerProxy(PersonBean person) {
        // 我们利用Proxy类的静态newProxyInstance方法创建代理对象(Java反射机制)
        return (PersonBean) Proxy.newProxyInstance(
                person.getClass().getClassLoader(),  // 将personBean的类载入器当作参数
                person.getClass().getInterfaces(),   // 代理需要实现的接口
                new OwnerInvocationHandler(person)); // 调用非拥有者的处理器
    }

获取非拥有者方法代理

    PersonBean getNonOwnerProxy(PersonBean person) {

        return (PersonBean) Proxy.newProxyInstance(
                person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
                new NonOwnerInvocationHandler(person));
    }

步骤四.测试类
测试配对服务系统。利用适当的代理包装任何PersonBean对象
MatchMakingTestDrive类

package com.practice.Test;
import java.lang.reflect.*;
import java.util.*;

import com.practice.Person.Impl.PersonBeanImpl;
import com.practice.Player.PersonBean;
import com.practice.Proxy.NonOwnerInvocationHandler;
import com.practice.Proxy.OwnerInvocationHandler;

public class MatchMakingTestDrive {
    // 实例变量, 当作是保存顾客的“数据库”
    Hashtable<String, PersonBean> datingDB = new Hashtable<String, PersonBean>();

    public static void main(String[] args) {
        MatchMakingTestDrive test = new MatchMakingTestDrive();
        test.drive();
    }

    public MatchMakingTestDrive() {
        // 在构造器中初始化数据库
        initializeDatabase();
    }

    public void drive() {
        PersonBean MW = getPersonFromDatabase("妙乌");  //从数据库中取出一个人
        PersonBean ownerProxy = getOwnerProxy(MW); // 创建这个人的拥有者代理
        System.out.println("账号拥有者的游戏ID " + ownerProxy.getPlayerID()); //  输出玩家昵称
        ownerProxy.setCommonHero("王昭君");  // 使用拥有者代理来设置自己常用英雄
        System.out.println("账号拥有者设置游戏常用英雄");
        System.out.println("账号拥有者常用的英雄:"+ownerProxy.getCommonHero());
        try {
            // 尝试用拥有者代理来给自己点赞
            ownerProxy.setYesNumber();
        } catch (Exception e) {
            // 如果给自己点赞会出错
            System.out.println("账号拥有者不能够给自己点赞");
        }
        System.out.println("账号总赞数为: " + ownerProxy.getYesNumber());

        System.out.println();

        // 创建一个非拥有者的代理
        PersonBean nonOwnerProxy = getNonOwnerProxy(MW);
        System.out.println("账号拥有者的游戏ID " + nonOwnerProxy.getPlayerID());
        try {
            // 尝试用非拥有者代理来设置常用英雄
            nonOwnerProxy.setCommonHero("妲己");
        } catch (Exception e) {
            // 不可以给别人设置常用英雄
            System.out.println("非拥有者不能设置别人的常用英雄");
        }
        // 可以给别人点赞
        nonOwnerProxy.setYesNumber();
        // 查看信息
        System.out.println("非拥有者玩家查看账号所有者信息:");
        System.out.println("昵称:" + nonOwnerProxy.getPlayerID() + "\t性别:" + nonOwnerProxy.getGender()
                + "\t常用英雄:" + nonOwnerProxy.getCommonHero());
        System.out.println("非拥有者玩家点赞");
        System.out.println("总赞数为: " + nonOwnerProxy.getYesNumber());
    }

    // 此方法需要一个person对象作为参数,然后返回该对象的代理
    // 因为代理和主题有相同的接口,所以我们返回接口PersonBean
    PersonBean getOwnerProxy(PersonBean person) {
        // 我们利用Proxy类的静态newProxyInstance方法创建代理对象(Java反射机制)
        return (PersonBean) Proxy.newProxyInstance(
                person.getClass().getClassLoader(),  // 将personBean的类载入器当作参数
                person.getClass().getInterfaces(),   // 代理需要实现的接口
                new OwnerInvocationHandler(person)); // 调用非拥有者的处理器
    }

    PersonBean getNonOwnerProxy(PersonBean person) {

        return (PersonBean) Proxy.newProxyInstance(
                person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
                new NonOwnerInvocationHandler(person));
    }

    PersonBean getPersonFromDatabase(String name) {
        return (PersonBean)datingDB.get(name);
    }

    // 初始化“数据库”
    void initializeDatabase() {
        PersonBean MW = new PersonBeanImpl();
        MW.setPlayerID("妙乌");
        MW.setGender("男");
        MW.setCommonHero("狄仁杰");
        MW.setAllCount(7);
        datingDB.put(MW.getPlayerID(), MW);

        PersonBean ZX = new PersonBeanImpl();
        ZX.setPlayerID("Kelly Klosure");
        ZX.setCommonHero("ebay, movies, music");
        ZX.setYesNumber();
        datingDB.put(ZX.getPlayerID(), ZX);
    }
}

运行结果:

七.源代码下载

从王者荣耀看设计模式(保护代理)

原文地址:https://www.cnblogs.com/miaowulj/p/12111133.html

时间: 2024-11-04 21:23:55

从王者荣耀看设计模式(保护代理模式)的相关文章

从王者荣耀看设计模式(虚拟代理模式)

从王者荣耀看设计模式(虚拟代理模式) 一.简介 王者荣耀游戏设置了很多种游戏模式,比如:王者模拟战.无限乱斗.梦境大乱斗.火焰山大战等.当从王者荣耀的主界面进入各类模式的界面时,由于网络原因,会存在一定程度的延时(会有一个圈圈在主界面一直转啊转啊转(??へ??╬)),直到加载完图片,会跳转到各模式界面. 二.虚拟代理(作为创建开销大的对象的代表) 虚拟代理是作为创建开销大的对象的代表.虚拟代理经常直到我们真正需要一个对象的时候才创建它.当对象在创建前和创建中时,由虚拟代理来扮演对象的替身.对象创

从王者荣耀看设计模式(九.命令模式)

从王者荣耀看设计模式(命令模式) 一.简介 王者荣耀是一款团队竞技游戏.良好的团队信息交流在一定程度上能帮助队伍取得胜利.为了保证游戏的流畅性与便捷性,王者荣耀提供了快捷交流机制,在王者小地图旁边有几个快捷聊天按钮(开始撤退,发起进攻,请求结合),玩家可通过点击快捷聊天按钮发出相应命令与队友进行交流 二.命令模式 命令模式(Command Pattern):命令模式是一种高内聚的模式,将"请求"封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.

从王者荣耀看设计模式(十四.工厂方法模式)

从王者荣耀看设计模式(工厂方法模式) 二.简介 王者荣耀游戏设计师根据英雄技能.属性.天赋等因素,将英雄划分为射手.辅助.打野.法师.坦克.战士等职业.一局比赛存在多类英雄可供选择.玩家在挑选游戏英雄时,合理的英雄职业搭配是赢得游戏胜利的基本保证. 三.工厂方法模式 工厂方法模式(Factory Method Pattern):工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式.在

从王者荣耀看设计模式(十七.原型模式)

从王者荣耀看设计模式(原型模式) 一.简介 王者荣耀包含有很多的玩法,其中有一种游戏模式只在周六和周日开放,那就是--克隆模式.与常规的游戏双方阵营只允许出现单一英雄不同,在克隆模式中,双方各选择一个英雄进行克隆,换句话说,一个阵营的五个人操作的五个相同的英雄 二.模式动机 在软件系统中,有些对象的创建过程比较复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在. 三.原型模式 原型模式

从王者荣耀看设计模式(十六.建造者模式)

从王者荣耀看设计模式(建造者模式) 一.简介 为了玩王者荣耀的游戏体验感,不少玩家都会选择花钱购买自己常用英雄的皮肤.一方面,购买的皮肤通常要比原画更加"炫酷".另一方面,购买的英雄皮肤常常伴随有特殊的回城特效与攻击技能特效. 二.模式动机 不管在生活中还是软件系统中,都存在一个包含多个组成部件的复杂对象,如汽车,它包括车轮.方向盘.发动机等各种部件.组成复杂对象的这些部件之间或许还会一定的约束,若某些属性没有赋值可能无法构成完整产品使用.如,电子邮件包含地址.收件人姓名.联系方式.创

从王者荣耀看设计模式(二十一.中介者模式)

从王者荣耀看设计模式(中介者模式) 一.简介 在王者荣耀中,有一个简单的聊天室,在聊天室中.玩家点击综合可以与全服的玩家发送消息,点击好友可向指定好友玩家私发信息.|??ω?` ) 二.模式动机 联合国是一个协调组织,各个国家就一些共同问题经由联合国进行协商,它取代了原本各个国家之间的直接交流,将各个成员国之间的强耦合关系转换为较为松散的耦合关系.在软件开发中,我们有时候也会需要使用类似联合国一样的中间对象来降低系统中类与类,对象与对象之间的耦合关系. 在本实例中,玩家与玩家多对多的通信,导致用

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

Java 设计模式_代理模式(2016-08-19)

概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 类图: 在代理模式中的角色: ● 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象. ● 目标对象角色:定义了代理对象所代表的目标对象. ● 代理对象角色:代理对象内部含有目标对象的