应用一(虚拟代理模式)
应用二(远程代理模式)
应用三(充值送好礼)
应用一:
在王者荣耀这款游戏里,设置有很多种娱乐游戏模式,比如:无限乱斗、梦境大乱斗、火焰山大战等。当从王者荣耀的主界面点击万象天工进入各类模式的界面时,由于网络原因,会存在一定程度的延时(即会有一个圈圈在主界面一直转啊转啊转),直到加载完才会跳转到各模式界面。
在本实例中,当图片还没有从加载完成时,使用虚拟代理进行代替,具体表示为:在图片没有下载到本地显示出来时,在GUI上显示一直转转转的圆圈,意味着"正在加载中……请稍后"。
虚拟代理是作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。
应用二:
在王者荣耀的登陆方式中,有QQ和微信两种登录方式,知道一个QQ或微信的号或密码就可以登录玩游戏,但是若一位玩家使用账号正在游戏中时,另一玩家登陆同一账号会导致前一玩家强制退出登陆!
在本实例中,通过远程代理,我们可以实现远程控制。当我处于在线状态时,使用代理让同一账号的使用者下线。
远程代理可以作为另一个JVM上对象的本地代表。调用代理的方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果返回给客户。
应用三:
王者荣耀每逢出新英雄皮肤、在重大节点时会有每日充值送好礼活动,每当有这么诱人的活动,许多氪金玩家甚至零冲党玩家本来是不打算充钱的,但是看到了只需充值1元就可以额外获得一皮肤碎片和30积分,想想真的就很划算,就会根据需要和能力充值相应的点券。当然,充值不同数目的点券得到的礼物自然不同。
在本实例中,依据玩家充值金额的不同返现不同的礼物。以此简单实例来描述是怎样使用代理模式的。
二、代理模式(Proxy Pattern)代理模式理解:
高度概括:为其他对象提供一种代理以控制对这个对象的访问。
当用户希望和某个对象打交道,但程序可能不希望用户直接访问该对象,而是提供一个特殊的对象,这个特殊的对象被称作当前用户要访问对象的代理,程序让用户和对象的代理打交道,即让用户通过访问代理来访问想要访问的对象。在代理模式中,代理的特点是它与所代理的对象实现了相同的接口,也就是说代理和它所代理的对象向用户公开了相同的方法,当用户请求代理调用这样的方法时代理可能需要验证某些信息或检查他所代理的对象是否可用,当代理确认他所代理的对象能调用相同的方法时,就把实际的方法调用委派给他所代理的对象,即让代理的对象调用同样的方法 。
代理模式结构中的三种角色:
①抽象主题(Subject):抽象主题是一个接口,该接口是对象和它的代理所共同的接口,即是RealSubject角色和Proxy角色实例所实现的接口;
②实际主题(RealSubject):实际主题是实现抽象主题接口的类,实际主体的实例是代理角色实例所要代理的对象;
③代理(Proxy):代理是实现抽象主题接口的类(代理和实际主题实现了相同的接口),代理含有主体接口声明的变量,该变量用来存放RealSubject角色的实例引用,这样一来,代理的实例就可以控制对它所包含的角色的RealSubject实例访问,即控制对它所代理对象的访问。
代理模式的UML类图:
代理模式的优缺点:
优点:
①代理模式可以屏蔽用户真正请求的对象,使用户程序和真正的对象之间解耦;
②使用代理来担当那些创建耗时的对象的替身;
③远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求;
④虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度;
⑤保护代理可以控制对真实对象的使用权限;
缺点:
①由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢;
②实现代理模式需要额外的工作。有些代理模式的实现非常复杂。
代理模式的适用情景:
①程序可能不希望用户直接访问该对象,而是提供一个特殊的对象,以控制对当前对象的访问;
②如果一个对象(例如很大的图像)需要很长时间才能加载完成;
③如果对象位于远程主机上,需要为用户提供访问该远程对象的能力。
eclipse结构图
主函数【应用(Application)】
Applicayion.java
package angle_proxyPattern1;
import java.net.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class Application {
ImageComponent imageComponent;
JFrame frame = new JFrame("王者荣耀页面加载模拟");
JMenuBar menuBar;
JMenu menu;
Hashtable cds = new Hashtable();
public static void main (String[] args) throws Exception {
new Application();
}
public Application() throws Exception{
cds.put("王者首页", "https://graph.baidu.com/resource/126029c103ffff3795c2c01577338115.jpg");
cds.put("王者模拟战","https://graph.baidu.com/resource/126cb98ad7a209b65c44701577338030.jpg");
cds.put("无限乱斗","https://graph.baidu.com/resource/12611c1da836e79b2398701577338223.jpg");
cds.put("梦境大作战","https://graph.baidu.com/resource/126a905124f61eaabb7ff01577338291.jpg");
cds.put("火焰山大作战","https://graph.baidu.com/resource/12694ce534e244577a20b01577338346.jpg");
cds.put("克隆大作战","https://graph.baidu.com/resource/12682b0f434812cf5613a01577338523.jpg");
cds.put("契约之战","https://graph.baidu.com/resource/126e137611a3bc598acc701577338585.jpg");
URL initialURL = new URL((String)cds.get("王者首页"));
menuBar = new JMenuBar();
menu = new JMenu("王者荣耀界面");
menuBar.add(menu);
frame.setJMenuBar(menuBar);
for(Enumeration e = cds.keys(); e.hasMoreElements();) {
String name = (String)e.nextElement();
JMenuItem menuItem = new JMenuItem(name);
menu.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
imageComponent.setIcon(new ImageProxy(getPicUrl(event.getActionCommand())));
frame.repaint();
}
});
}
Icon icon = new ImageProxy(initialURL);
imageComponent = new ImageComponent(icon);
frame.getContentPane().add(imageComponent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
frame.setVisible(true);
}
URL getPicUrl(String name) {
try {
return new URL((String)cds.get(name));
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
}
ImageComponent.java
package angle_proxyPattern1;
import java.awt.*;
import javax.swing.*;
class ImageComponent extends JComponent {
private static final long serialVersionUID = 1L;
private Icon icon;
public ImageComponent(Icon icon) {
this.icon = icon;
}
public void setIcon(Icon icon) {
this.icon = icon;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w = icon.getIconWidth();
int h = icon.getIconHeight();
int x = (800 - w)/2;
int y = (600 - h)/2;
icon.paintIcon(this, g, x, y);
}
}
ImageProxy.java
package angle_proxyPattern1;
import java.awt.Component;
import java.awt.Graphics;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.ImageIcon;
public class ImageProxy implements Icon {
ImageIcon imageIcon;
URL imageURL;
Thread retrievalThread;
boolean retrieving = false;
public ImageProxy(URL url) {
imageURL = url;
}
public int getIconWidth() {
if (imageIcon != null) {
return imageIcon.getIconWidth();
} else {
return 800;
}
}
public int getIconHeight() {
if (imageIcon != null) {
return imageIcon.getIconHeight();
} else {
return 600;
}
}
public void paintIcon(final Component c, Graphics g, int x, int y) {
if (imageIcon != null) {
imageIcon.paintIcon(c, g, x, y);
} else {
g.drawString("游戏界面加载中,请稍后...", x + 300, y + 190);
if (!retrieving) {
retrieving = true;
retrievalThread = new Thread(new Runnable() {
public void run() {
try {
imageIcon = new ImageIcon(imageURL, "GamePage");
c.repaint();
} catch (Exception e) {
e.printStackTrace();
}
}
});
retrievalThread.start();
}
}
}
}
运行结果截图
eclipse结构图
主函数【应用(Application)】
Client.java
package angle_proxyPattern2;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
public static int flag = 0;
public static void main(String[] args){
new Thread(new Runnable() {
public void run() {
try {
AccountStatus accountStatus;
accountStatus = (AccountStatus)Naming.lookup("rmi://127.0.0.1:9090/AccountStatusHelper");
accountStatus.OnlineStatus();
Thread.sleep(1000);
if(flag == 1) {
accountStatus.OfflineStatus();
}
} catch (NotBoundException | MalformedURLException | RemoteException | InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println("玩家2通过QQ登陆王者荣耀");
flag = 1;
}
}
远程接口类
AccountStatus.java
package angle_proxyPattern2;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface AccountStatus extends Remote {
public void OnlineStatus() throws RemoteException;
public void OfflineStatus() throws RemoteException;
}
接口实现类
AccountStatusHelper.java
package angle_proxyPattern2;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class AccountStatusHelper extends UnicastRemoteObject implements AccountStatus {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unused")
private boolean Online = false;
public AccountStatusHelper(boolean _Online) throws RemoteException {
this.Online = _Online;
}
@Override
public void OnlineStatus() throws RemoteException {
System.out.println("玩家1正使用账号游戏中……");
}
@Override
public void OfflineStatus() throws RemoteException {
System.out.println("玩家1退出王者荣耀账号!");
}
}
服务类
Server.java
package angle_proxyPattern2;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
*/
public class Server {
private static final String HOST = "localhost";
private static final int PORT = 9090;
public static void main(String [] args) {
try {
//创建对象, 准备将这个对象作为远程对象注册
AccountStatus accountStatusHelper = new AccountStatusHelper(true);
LocateRegistry.createRegistry(PORT);
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://" + HOST + ":" + PORT + "/AccountStatusHelper",accountStatusHelper);
System.out.println("---->远程对象绑定成功!");
}catch(RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
}catch(AlreadyBoundException e) {
System.out.println("发生重复绑定对象异常!");
e.printStackTrace();
}catch(MalformedURLException e) {
System.out.println("发生URL畸形异常!");
e.printStackTrace();
}
}
}
运行结果截图
eclipse结构图
主函数【应用(Application)】
Applicayion.java
package angle_proxyPattern3;
import angle_proxyPattern3.GiveReward;
import java.util.Scanner;
public class Application{
public static void main(String args[]) {
Scanner reader=new Scanner(System.in);
System.out.println("您要充值的点券数是:");
int a;
a=reader.nextInt();
Charge10Money money=new Charge10Money();
money.setMoney(a);
money.getRewards();
}
}
抽象主题
ChargeMoney.java
package angle_proxyPattern3;
public interface ChargeMoney{
public void getRewards();
}
具体模板
GiveReward.java
package angle_proxyPattern3;
public class GiveReward implements ChargeMoney{
int a;
public GiveReward(int a) {
this.a=a;
}
public void getRewards(){
System.out.println("恭喜您!成功充值"+a+"点券!");
System.out.println("额外赠送1张荣耀积分抽奖券+3个皮肤碎片");
}
}
代理
Charge10Money.java
package angle_proxyPattern3;
import angle_proxyPattern3.ChargeMoney;
import angle_proxyPattern3.GiveReward;
public class Charge10Money implements ChargeMoney{
int a;
GiveReward rewards;
public void setMoney(int a) {
this.a=a;
}
public void getRewards(){
if(a==10){
rewards=new GiveReward(a);
rewards.getRewards();
}
else
{System.out.println("充值失败!请重试……");}
}
}
运行结果截图
更多设计模式在王者荣耀中的应用请点击我的→设计模式在王者荣耀中的应用专栏。
感谢阅读
END