更适合Swing程序的MVC方案
MVC有MVC1和MVC2的区别,它们的区别在于MVC1中用Model来通知View进行改变,而MVC2中使用Controller来通知View.在桌面程序中一般采用MVC1,而Web程序多采用MVC2,这是因为web程序中,Model无法知道View的原因.在Swing程序中,我们通常采用让View实现Observer接口,让Model继承Observable类来实现MVC1,而让Controller把它们创建及连接起来,具体代码如下:
public
class
XXXControl
{
private XXXModel model = null;
private XXXView view = null;
public XXXControl() {
model = new XXXModel();
view = new XXXView();
model.addObserver(view);
}
.
.
.
}
private XXXModel model = null;
private XXXView view = null;
public XXXControl() {
model = new XXXModel();
view = new XXXView();
model.addObserver(view);
}
.
.
.
}
而Model进过处理后得到了结果,它采用Observable的notifyObservers()方法来通知View进行改变,而View的public void update(Observable o, Object arg)方法将相应这一改变,它通过解析Observable类型的对象o得到处理结果,再进行具体的表现层改变.
粗看起来MVC各司其职,很完美,但还有不和谐的隐患:
1.View必须知道解析Model,造成了二者的耦合.
2.View非得实现Observer接口,Model非得继承Observable类,这个处理不是必要的.
3.这种模式只适合即时处理,即相应很快的处理,对于耗时过程并不适合.
4.由于Model中数据众多,很多时候我们还需要建立一个常量类来区分各种情况和决定View更新的地方,进一步加重了类之间的耦合程度.
综上,我觉得对于稍大的Swing程序,MVC2+线程回调方式更适合,它的主要处理是:
1.依然由Controller创建View和Model,它们担负的职责也和原来一样,但是View不实现Observer接口,Model不继承Observable类,它们该怎么样还是怎么样,而让Controller来充当它们之间的中介者.
2.如果是即时处理,可以在Controller中添加事件处理时就直接写来.如果是耗时处理,可以将View和Model的引用(或Model中元素的引用)传递给一个线程处理类,具体的运算和界面反应在线程处理类中完成.
下面是一个调用例子:
new FetchTablesThread(model.getDataSource(), view,schema).start();
下面是线程类的例子:
public
class
FetchTablesThread
extends
BaseThread
{
private static Logger logger = Logger.getLogger(FetchTablesThread.class);
private String schema;
public FetchTablesThread(DataSource dataSource, SqlWindowView view,
String schema) {
super(dataSource, view);
this.schema = schema;
}
public void run() {
OutputPanel outputPanel = view.getTabbedPanel().getInputOutputPanel().getOutputPanel();
try {
if (dataSource.getDbtype().equals("mysql")) {
// Specail Process for MySql
new FetchTables4MySqlThread(dataSource, view, schema).start();
} else {
// Ordinary Process for other DB
List tables = dataSource.getTablesInSchema(schema);
if (tables.size() > 0) {
// Find tables under schema
view.getCatalogTablesPanel().getMultiTable().refreshTable(
tables);
outputPanel.showText(true);
String text = "Find " + tables.size()
+ " tables under schema:" + schema
+ " successfully!";
outputPanel.appendOutputText(text);
logger.info(text);
} else {
// Can't find tables under schema
outputPanel.showText(true);
String text = "Can't find any table under schema:" + schema;
outputPanel.appendOutputText(text);
logger.info(text);
}
}
} catch (Exception ex) {
outputPanel.showText(true);
String text = "Can't find any table under schema:" + schema+" and errorMsg="+ex.getMessage();
outputPanel.appendOutputText(text);
logger.info(text);
}
}
}
private static Logger logger = Logger.getLogger(FetchTablesThread.class);
private String schema;
public FetchTablesThread(DataSource dataSource, SqlWindowView view,
String schema) {
super(dataSource, view);
this.schema = schema;
}
public void run() {
OutputPanel outputPanel = view.getTabbedPanel().getInputOutputPanel().getOutputPanel();
try {
if (dataSource.getDbtype().equals("mysql")) {
// Specail Process for MySql
new FetchTables4MySqlThread(dataSource, view, schema).start();
} else {
// Ordinary Process for other DB
List tables = dataSource.getTablesInSchema(schema);
if (tables.size() > 0) {
// Find tables under schema
view.getCatalogTablesPanel().getMultiTable().refreshTable(
tables);
outputPanel.showText(true);
String text = "Find " + tables.size()
+ " tables under schema:" + schema
+ " successfully!";
outputPanel.appendOutputText(text);
logger.info(text);
} else {
// Can't find tables under schema
outputPanel.showText(true);
String text = "Can't find any table under schema:" + schema;
outputPanel.appendOutputText(text);
logger.info(text);
}
}
} catch (Exception ex) {
outputPanel.showText(true);
String text = "Can't find any table under schema:" + schema+" and errorMsg="+ex.getMessage();
outputPanel.appendOutputText(text);
logger.info(text);
}
}
}
这样做有两个好处一是使程序结构松散化,适于修改,二是相对传统的MVC2,Controller中事件处理的代码也容易变得简单而清晰,可维护性更佳.
综上,我认为MVC2+线程回调方式是一种值得推荐的Swing桌面程序写法.
关于线程回调方式,您可以参考:
http://www.blogjava.net/sitinspring/archive/2007/06/28/126809.html
关于MVC,您可以参考:
http://junglesong.yculblog.com/post.2665424.html