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

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

一.简介

王者荣耀游戏设置了很多种游戏模式,比如:王者模拟战、无限乱斗、梦境大乱斗、火焰山大战等。当从王者荣耀的主界面进入各类模式的界面时,由于网络原因,会存在一定程度的延时(会有一个圈圈在主界面一直转啊转啊转(•́へ•́╬)),直到加载完图片,会跳转到各模式界面。

模式动机
在本实例中,当图片还没有从网上下载完成,使用虚拟代理进行代替,具体表示为:在图片没有下载到本地显示出来时,在GUI上显示:“正在加载中……请稍后”

二.虚拟代理(作为创建开销大的对象的代表)

虚拟代理是作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。

三.结构图

四.设计类图

五.顺序图

六.ImageProxy如何工作

⑴. 我们创建一个用来显示的ImageProxy代理,paintIcon()方法会被调用,而ImageProxy会产生线程取得图像,并创建ImageIcon.

⑵. 在某个时间点,也就是图片下载完成后,图像被返回,ImageIcon被完整实例化。

⑶. 在ImageIcon被创建后,下次调用paintIcon时,代理就委托ImageIcon进行。

七.代码实现

编写ImageProxy代码

package com.practice.VirtualProxy;

import java.awt.Component;
import java.awt.Graphics;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.ImageIcon;
 
//实现Icon接口
public class ImageProxy implements Icon {
	ImageIcon imageIcon;
	URL imageURL;
	Thread retrievalThread;
	boolean retrieving = false;
 
	// 将图片的URL传入构造器中
	public ImageProxy(URL url) {
		imageURL = url;
	}
 
	// 在图像加载完毕前,返回默认的宽和高
	// 图像加载完毕后,装给iamgeIcon处理
	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) {
		// 如果已经有了icon,就画出
		if (imageIcon != null) {
			imageIcon.paintIcon(c, g, x, y);
		} else {
			// 还没有icon时,就显示“加载中...”的消息
			g.drawString("游戏界面加载中,请稍后...", x + 300, y + 190);
			if (!retrieving) {
				retrieving = true;
				
				// 在这个线程中加载真正的icon图像。注意,加载图像和ImageIcon是同步(synchronous)
				// 也就是说,只有在加载完之后,ImageIcon构造器才会返回。这样,我们的程序会耗在这里
				// 所以要把加载变成异步(asynchronous)的。
				retrievalThread = new Thread(new Runnable() {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          					        
                                        public void run() {
						try {
							imageIcon = new ImageIcon(imageURL, "GamePage");
							c.repaint();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}    
				});
				retrievalThread.start();
			}
		}
	}
 
}

编写ImageComponent(用来放到frame布局中用来显示图片)

package com.practice.VirtualProxy;

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);
	}
}

测试代码ImageProxyTestDrive

package com.practice.VirtualProxy;

import java.net.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
 
public class ImageProxyTestDrive {
	ImageComponent imageComponent;
	JFrame frame = new JFrame("王者荣耀页面加载器");
    JMenuBar menuBar;  // 菜单栏
    JMenu menu;   	   // 菜单 
	Hashtable<String, String> cds = new Hashtable<String, String>();
 
	public static void main (String[] args) throws Exception {
		new ImageProxyTestDrive();
	}
 
	public ImageProxyTestDrive() throws Exception{
		// 构造菜单项用的, key=CD名,  value=URL
		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");
 
        // 设置初始的CD封面
		//URL initialURL = new URL((String)cds.get("Once<曾经>"));
        URL initialURL = new URL((String)cds.get("王者首页"));
		// 建立菜单栏
		menuBar = new JMenuBar();
		menu = new JMenu("王者荣耀界面");
        menuBar.add(menu);
        
        frame.setJMenuBar(menuBar);
 
		for(Enumeration<String> 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();
           	      }
        	});
		}
 		
		// set up frame and menus
 
		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;
		}
	}
}
八.源代码下载

!从王者荣耀看设计模式

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值