问题来自HeadFirst设计模式第11章代理模式468页的设计谜题:
ImageProxy类似乎有两个有条件语句控制的状态,你能否用另一个设计模式清理这样的代码?你要如何重新设计ImageProxy?
思路:
我们可以使用状态模式:实现两个状态,分别是ImageLoaded和ImageUnloaded。然后把if语句内的代码放进去各自的状态中。一开始的状态是ImageLoaded,当ImageIcon取回后就转换道ImageLoaded状态。
下面是自己写的一段参考代码
State类
扩展Icon接口,只是单纯的改个接口名字方便理解
Icon是JavaAPI的内置接口,负责处理图片。
package com.julian.delegatePattern.virtualProxy;
import javax.swing.*;
public interface State extends Icon {}
ImageUnloaded类
如果图片未加载,调用该类。
先打印一行字“Loading CD Cover, please wait...”提醒用户等待。
接着开启新线程加载图片,并修改ImageProxyState的状态为ImageLoaded。
package com.julian.delegatePattern.virtualProxy;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class ImageUnloaded implements State {
ImageProxyState imageProxyState;
public ImageUnloaded(ImageProxyState imageProxyState) {
this.imageProxyState = imageProxyState;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawString("Loading CD Cover, please wait...",x+ 300, y + 190);
if (!imageProxyState.isRetrieving()){
imageProxyState.setRetrieving(true);
//open a sub-Thread to load photo
Thread retrievalThread = new Thread(new Runnable() {
@Override
public void run() {
try{
ImageIcon imageIcon = new ImageIcon(imageProxyState.getImageURL(),"CD Cover");
imageProxyState.setImageIcon(imageIcon);
c.repaint();//repaint(0, 0, 0, width, height);
}catch (Exception e){
e.printStackTrace();
}
}
});
imageProxyState.setRetrievalThread(retrievalThread);
imageProxyState.startThread();
}
imageProxyState.setCurrentState(imageProxyState.imageLoaded);
}
@Override
public int getIconWidth() {
return 800;
}
@Override
public int getIconHeight() {
return 600;
}
}
ImageLoaded类
如果图片已经加载了,那么调用该类加载图片
package com.julian.delegatePattern.virtualProxy;
import javax.swing.*;
import java.awt.*;
public class ImageLoaded implements State {
ImageProxyState imageProxyState;
public ImageLoaded(ImageProxyState imageProxyState) {
this.imageProxyState = imageProxyState;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
imageProxyState.paintIconByImageIcon(c,g,x,y);
}
@Override
public int getIconWidth() {
return imageProxyState.getIconWidthByImageIcon();
}
@Override
public int getIconHeight() {
return imageProxyState.getIconHeightByImageIcon();
}
public void setImageIcon(ImageIcon imageIcon) {
this.imageProxyState.setImageIcon(imageIcon);
}
}
ImageProxyState
Icon的代理类。有两个State状态 imageLoaded和 imageUnloaded。
当调用它的方法时,会委托给它当前状态处理。
package com.julian.delegatePattern.virtualProxy;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class ImageProxyState implements Icon {
State imageLoaded;
State imageUnloaded;
State currentState;
ImageIcon imageIcon;
URL imageURL;
Thread retrievalThread;
boolean retrieving = false;
public ImageProxyState(URL imageURL) {
this.imageURL = imageURL;
imageLoaded = new ImageLoaded(this);
imageUnloaded = new ImageUnloaded(this);
currentState = imageUnloaded;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
currentState.paintIcon(c,g,x,y);
}
@Override
public int getIconWidth() {
return currentState.getIconWidth();
}
@Override
public int getIconHeight() {
return currentState.getIconHeight();
}
public boolean isRetrieving() {
return retrieving;
}
public void setCurrentState(State currentState) {
this.currentState = currentState;
}
public void setImageIcon(ImageIcon imageIcon) {
this.imageIcon = imageIcon;
}
public URL getImageURL() {
return imageURL;
}
public void setRetrievalThread(Thread retrievalThread) {
this.retrievalThread = retrievalThread;
}
public void setRetrieving(boolean retrieving) {
this.retrieving = retrieving;
}
public void startThread(){
retrievalThread.start();
}
public int getIconWidthByImageIcon(){
return imageIcon.getIconWidth();
}
public int getIconHeightByImageIcon(){
return imageIcon.getIconHeight();
}
public void paintIconByImageIcon(Component c, Graphics g, int x, int y){
imageIcon.paintIcon(c,g,x,y);
}
}
ImageProxyStateTestDrive
建立框架和菜单并测试代码
package com.julian.delegatePattern.virtualProxy;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
public class ImageProxyStateTestDrive {
ImageComponent imageComponent;
JFrame jFrame = new JFrame("CD Cover Viewer");//set the title for the frame
JMenuBar jMenuBar;
JMenu jMenu;
Hashtable cds = new Hashtable();
public static void main(String[] args) throws Exception {
ImageProxyStateTestDrive imageProxyTestDrive = new ImageProxyStateTestDrive();
}
public ImageProxyStateTestDrive() throws Exception {
cds.put("Ballet Pose","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1736727202,1355489933&fm=26&gp=0.jpg");
cds.put("Naruto","https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1062924988,1223376387&fm=26&gp=0.jpg");
cds.put("Selected Ambient Works, Vol. 2","https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1265870196,2883097596&fm=26&gp=0.jpg");
cds.put("kimonoBaiDu","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1598667455000&di=c90ebc533f1a4e1109a18d52ee353ee7&imgtype=0&src=http%3A%2F%2Fhbimg.b0.upaiyun.com%2F454d60b63dbc3858331bbc4bc8757aef329e5b59231b6-bcV3m4_fw658");
URL initialURL = new URL((String)cds.get("Selected Ambient Works, Vol. 2"));
jMenuBar = new JMenuBar();
jMenu = new JMenu("fAVORITE cds");//set the title of the menu
jMenuBar.add(jMenu);
jFrame.setJMenuBar(jMenuBar);
for (Enumeration e = cds.keys();e.hasMoreElements();){
String name = (String)e.nextElement();
JMenuItem jMenuItem = new JMenuItem(name);
jMenu.add(jMenuItem);
jMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
imageComponent.setIcon(new ImageProxyState(getCDUrl(e.getActionCommand())));
jFrame.repaint();
}
});
}
//建立框架和菜单build frame and menu
Icon icon = new ImageProxyState(initialURL);
imageComponent = new ImageComponent(icon);
jFrame.getContentPane().add(imageComponent);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(1000,800);
jFrame.setVisible(true);
jFrame.setLocation(450,100);
}
URL getCDUrl(String name){
try {
return new URL((String)cds.get(name));
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
}




京公网安备 11010502036488号