三十九:仮想エージェントモード


一:ロード遅延
皆さんもこのような状況に遭遇したと思います.一つのシステムにはモジュールをロードする必要がありますが、このモジュールのロードにはかなりの時間がかかります.そのため、システムは「ロード中」の情報を表示し、同時にモジュールをロードし、モジュールをロードした後、システムは「ロード中」の文字をキャンセルし、このモジュールを起動します.一般的な例はNetscapeブラウザです.JBuilderなどの大型ソフト.1つの画像をロードしても時間が遅れる場合がありますので、画像を置く場所に文字情報を置く必要があります.ユーザーは心を込めて待ってください.システムは別のスレッドに画像をロードするが、画像のロードが完了すると、待機情報をこの画像に変換する.これをロード遅延と呼び、ロード遅延は明らかに友好的なユーザインタフェースの設計案である.
二:仮想エージェントモードの応用
実際のトピックオブジェクトのロードにリソースがかかる場合、仮想エージェントオブジェクトは、実際のオブジェクトをエージェントする要求を受け入れることができ、要求を受けると、エージェントオブジェクトはすぐに「ロード中」の情報を発行し、適切なときに実際のトピックオブジェクト、すなわちモジュールまたは画像をロードすることができる.この章では、画像のロードには一定のリソースがかかるため、画像オブジェクトの代わりにクライアントからの要求を受け付ける仮想エージェントオブジェクトを設計する必要がある、仮想エージェントオブジェクトが要求を受けると、所定の論理ヘッダに従って待機情報を表示し、別のスレッドに画像をロードする.画像のロードが完了すると、メインスレッドが画像を表示することを決定する.
三:システムの設計
システムは、JFrameオブジェクトと、Iconオブジェクトと、このIconオブジェクトの仮想エージェントオブジェクトからなる.システムのクライアント・オブジェクトは、エージェントImageIconProxyオブジェクトを呼び出します.このエージェントは、呼び出しを実際のトピック・ロール、すなわちImageIconオブジェクトに渡す役割を果たします.クライアントがエージェントImageIconProxyオブジェクトを呼び出すと、このエージェントオブジェクトが受信したGraphicsオブジェクトを呼び出すdrawRec()メソッドに「Loading photo.」が表示されます.エージェントオブジェクトが内部スレッドオブジェクトを作成し、SwingUtilitiesのinvokeLater()メソッドに転送することで、エージェントオブジェクトが実際のトピックをロードする責任を負うようになり、エージェントオブジェクトが実際のトピックのロードを遅らせることに成功する、その後、エージェントトピックは実際のトピックを表示するタイミングが成熟したと判断し、実際のトピック(すなわち画像)を表示する.
次に、システムのソースコードを示します.
package cai.milenfan.basic.test; 

import java.awt.Component; 
import java.awt.Graphics; 

import javax.swing.Icon; 
import javax.swing.ImageIcon; 
import javax.swing.SwingUtilities; 

public class ImageIconProxy implements Icon{ 
private ImageIcon realIcon = null; 
private String imageName; 
private int width; 
private int height; 
boolean isIconCreated = false; 

public ImageIconProxy(String imageName,int width,int height){ 
this.imageName = imageName; 
this.width = width; 
this.height = height; 
} 

public int getIconHeight() { 
return realIcon.getIconHeight(); 
} 

public int getIconWidth() { 
return realIcon.getIconWidth(); 
} 

//    
public void paintIcon(final Component c, Graphics g, int x, int y) { 
if(isIconCreated){ 
realIcon.paintIcon(c, g, x, y); 
g.drawString("Java and Patterns by Milenfan", x 20, y 370); 
}else{ 
g.drawRect(x, y, width-1, height-1); 
g.drawString("Loading...", x 20, y 20); 
//             
synchronized(this){ 
SwingUtilities.invokeLater(new Runnable(){ 
public void run() { 
try { 
//         ,     
Thread.currentThread().sleep(2000); 
//     
realIcon = new ImageIcon(imageName); 
isIconCreated = true; 
} catch (InterruptedException e) { 
e.printStackTrace(); 
} 
//         ,        
c.repaint();//c  final  
}}); 
} 
} 
} 

} 
package cai.milenfan.basic.test; 

import javax.swing.Icon; 
import javax.swing.JFrame; 
import java.awt.Graphics; 
import java.awt.Insets; 

public class Client extends JFrame{ 
private static int IMAGE_WIDTH = 400; 
private static int IMAGE_HEIGHT = 300; 
private Icon imageIconProxy = null; 

public Client(){ 
super("             ..."); 
imageIconProxy = new ImageIconProxy("c:/ZK-Logo.gif",IMAGE_WIDTH,IMAGE_HEIGHT); 
setBounds(100,100,IMAGE_WIDTH 10,IMAGE_HEIGHT 30); 
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
} 

//  java.awt.Container   
public void paint(Graphics g){ 
super.paint(g); 
Insets insets = getInsets(); 
imageIconProxy.paintIcon(this, g, insets.left, insets.top); 
} 

static public void main(String[] args){ 
Client app = new Client(); 
app.show(); 
} 
} 

例ではSwingUtilitiesを用いる.invokeLater()メソッドは独立した新しいスレッドを開き、新しいタスクを実行するために使用される.この新しいタスクは、まず2秒間休眠し、画像をロードし、ロードが完了した後にウィンドウを再描画することである.SwingUtilitiesには、新しいスレッドのタスクが完了するまでメインスレッドの実行をブロックするinvokeLater()メソッドと似た方法がある.
このモードはとても実用的です..