SwingでUIアーキテクチャパターン Supervising Controller編
今回はMVPパターンのうちSupervising Controllerと言われるパターンで「BMIによる肥満度判断」のサンプルを実装してみます。
前回のMVCパターンで問題となったプレゼンテーションの状態・ロジックを持つのがプレゼンターになります。また、MVCのビューはモデルの更新を受けて、ビュー自身が表示を更新を行いますが、Supervising Controllerではプレゼンターがプレゼンテーションロジックに関してビューを更新することができます。
では早速プレゼンターからコードを見ていきます。
public class Presenter{ private boolean notifyEvent; private View view; private Model model; public Presenter( View view ){ this.view = view; } public void setModel( Model model ){ this.model = model; } public Model getModel(){ return model; } public boolean isNotifyEvent(){ return notifyEvent; } public void heightChanged( DocumentEvent e ){ String text = getTextWithDocumentEvent( e ); heightChanged( text ); } public void heightChanged( String newHeight ){ notifyEvent = true; try{ model.setHeight( newHeight ); updateColor(); } finally{ notifyEvent = false; } } public void weightChanged( DocumentEvent e ){ String text = getTextWithDocumentEvent( e ); weightChanged( text ); } public void weightChanged( String newWeight ){ notifyEvent = true; try{ model.setWeight( newWeight ); updateColor(); } finally{ notifyEvent = false; } } private void updateColor(){ float bmi; try{ bmi = Float.parseFloat( model.getBmi() ); } catch ( NumberFormatException ignored ){ return; } Color bmiColor; if( bmi < 18.5f ){ bmiColor = Color.WHITE; } else if( bmi < 20.0f ){ bmiColor = Color.YELLOW; } else if( bmi < 30.0f ){ bmiColor = Color.ORANGE; } else{ bmiColor = Color.RED; } view.setBmiBackground( bmiColor ); } private String getTextWithDocumentEvent( DocumentEvent e ){ try{ return e.getDocument().getText( 0, e.getDocument().getLength() ); } catch ( BadLocationException ignored ){ return ""; } } }
前回のMVCパターンでは、モデルに実装していたBMIを表示するテキストボックスの背景色に関するロジックですが、今回のSupervising Controllerではこのプレゼンターに実装しています。
プレゼンターではユーザからのイベントをモデルに渡した後、updateColor()でBMIを表示するテキストボックスの背景色を計算してビューを直接更新しています。
public class Model{ private EventListenerList listenerList = new EventListenerList(); private String height = ""; private String weight = ""; private String bmi = ""; public String getWeight(){ return weight; } public String getHeight(){ return height; } public String getBmi(){ return bmi; } public void setWeight( String weight ){ this.weight = weight; updateBMI(); fireModelChanged(); } public void setHeight( String height ){ this.height = height; updateBMI(); fireModelChanged(); } private void updateBMI(){ float height; float weight; try{ height = Float.valueOf( this.height ); weight = Float.valueOf( this.weight ); } catch ( NumberFormatException e ){ return; } if( height == 0f ){ return; } float bmi = weight / ( height * height ); this.bmi = Float.toString( bmi ); } protected void fireModelChanged(){ ModelListener[] listeners = listenerList.getListeners( ModelListener.class ); ModelEvent event = new ModelEvent( this ); for( ModelListener l : listeners ){ l.modelChanged( event ); } } public void addModelListener( ModelListener listener ){ listenerList.add( ModelListener.class, listener ); } public void removeModelListener( ModelListener listener ){ listenerList.remove( ModelListener.class, listener ); } }
結果モデルからはプレゼンテーションに関するロジックが無くなり、純粋なドメインオブジェクトのクラスになりました。
ビューはBMIを表示するテキストボックスの背景色のセッターが追加されただけなので、ここではコードは省略します。
次回は、Passive Viewパターンです。
今回のコードはこちらです。
ソース一式(github)