这么多设计模式,我的看法和理解

一直在做与数据库相关的企业应用,感觉到用的最多的设计模式是
Factory和Singleton

而什么观察者模式啊,桥模式,好象根本没什么用,不过最近在用awt,感觉到java的awt实现用了这些模式,不知道为什么要这样用

首先我是一个模式设计低手,我想说的一点自己的体会就是,就拿观察者模式并不是那么简单,其实观察者模式可以应用在底层的代码(java bean)可以方便一些类间存在触发/调用(类的事件)关系(虽然不用模式也可以实现,但是运用观察者模式代码量减少,类的偶合关系就更小)。我个人感觉模式的运用千变万化,别人说的模式例子只是想说明模式适用方面(精髓)但是在自己应用的时候可以先考虑系统要实现的场景有没有适用的模式(广的方面,小的方面也是这样)。

我最近也在研究模式。
我对模式的理解就是:
一句话可以用白话讲,很长
而如果这个含义可以用成语讲,岂不是更妙?

模式就和成语一样,只是不同领域有不同的用途。
适合用成语的时候,可以用,但是不适合的时候还是讲白话吧。
所以我很注重模式的应用场景,以及模式的组成,这两者必须熟练了
才能用的很熟。

一个成语,如果不了解其含义,我想谁也不会用吧?
同样,对于模式,仅仅知道模式的名字是不行的
了解含义也就是 应用场景和模式的组成
是使用的前提。

大家理解非常棒,希望更多人发表自己的看法,用自己的语言。

Design Pattern Practice

1.序
本文从一个简单的多列排序的例子入手,由浅入深地讲解Design Pattern(设计模式)的目的、分析和实践。
文中的例子用到Compositor Pattern和Decorator Pattern。
同时,文中的例子也提供了一类问题(条件组合问题)的解决方案。

2.问题的引入
Design Pattern(设计模式)的目标是,把共通问题中的不变部分和变化部分分离出来。不变的部分,就构成了Design Pattern(设计模式)。这一点和Framework(框架)有些象。
下面举个排序的例子,说明如何抽取问题中的不变部分。
假设一个Java类Record有field1,field2,field3等字段。


public class Record{
public int field1;
public long field2;
public double filed3;
};

我们还有一个Record对象的数组Record[] records。我们需要对这个数组按照不同的条件排序。
首先,按照field1的大小从小到大进行升序排序。
排序函数如下:


void sort(Record[] records){
for(int i =…){
for(int j=…){
if(records[ i ].field1 > records[ j ].field1)
// swap records[ i ] and records[ j ]
}
}
}

其次,按照field2的大小从小到大进行升序排序。


void sort(Record[] records){
for(int i =…){
for(int j=…){
if(records[ i ].field2 > records[ j ].field2)
// swap records[ i ] and records[ j ]
}
}
}

再次,按照field3的大小从小到大进行升序排序。
...
这种要求太多了,我们写了太多的重复代码。我们可以看到,问题的变化部分,只有判断条件部分(黑体的if条件判断语句)。
我们可以引入一个Comparator接口,把这个变化的部分抽取出来。


public interface Comparator(){
public boolean greaterThan(Record a, Record b);
};

sort函数就可以这样写(把判断条件作为参数):


void sort(Record[] records, Comparator compare){
for(int i =….){
for(int j=….){
if(compare.greaterThen(records[ i ], records[ j ]))
// swap records[ i ] and records[ j ]
}
}
}

这样,对应第一个要求――对records数组按照field1的大小排序。
我们可以做一个实现Comparator接口的CompareByField1类。


public class CompareByField1 implements Comparator{
public boolean greaterThan(Record a, Record b){
if(a.filed1 > b.filed1){
return ture;
}
return false;
}
}

sort函数的调用为:


sort(records, new CompareByField1());

这样,对应第一个要求――对records数组按照field2的大小排序。
我们可以做一个实现Comparator接口的CompareByField2类。


public class CompareByField2 implements Comparator{
public boolean greaterThan(Record a, Record b){
if(a.filed2 > b.filed2){
return ture;
}
return false;
}
}
[code]

sort函数的调用为:
[code]
sort(records, new CompareByField2());

按照C++ STL的叫法,这里的sort称为算法(Algorithm),records称为容器(集合),Comparator称为函数对象(Function Object)。

JDK的java.util.Collections类的sort方法和java.util.Comparator接口就是按照这样的思路设计的。下面我们来看看如何应用sort和Comparator解决多列排序问题。

3.多列排序问题

3.1排序条件的数量

我们知道,SQL语句能够实现强大的排序功能,能够按照不同字段的排列进行排序,也能够按照升序,降序排序。比如下面的语句。
order by field1 asc, field2 asc, field3 desc。

这个排序条件按照field1的升序,field2的升序,field3的降序排序。
注意,排在前面的字段具有较高的优先级。
比如,两条纪录A和B,满足如下条件:
(1)A.field1 > B.field1,(2)A.field2 < B.field2。
这时如果按照order by field1, field2语句排序,那么 A > B。
如果上述条件中的(1)A.field1 > B.field1变化为A.field1 == B.field1。这时,条件(2)就会起作用。这时,A < B。

我们来看看在Java中如何实现这种灵活而强大的排序。
我们还是以上一节的Record类为例。Record类有3个字段,我们来看一看,有多少种可能的排序条件。
(1)按field1排序。(2)按field2排序。(3)按field3排序。(4)按field1,field2排序。(5)按field1升序,按field2降序排序…...

各种排序条件的排列组合,大概共有30种。而且,随着字段个数的增长,排序条件的个数呈幂级数的增长。
按照上一节的sort和Comparator方法,如果我们需要达到按照任意条件进行排序的目的,那么我们需要为每一个排序条件提供一个Comparator,我们需要30个Comparator类。:-)

当然,我们不会这么做,我们能够进一步提取这个问题中的相同重复部分,优化我们的解决方案。

3.2 问题分析
我们来分析这个问题中变化的部分和不变的部分。
上面所有的排序条件中,不变的部分有3部分:
(1)A.field1和B.field1的比较,
(2)A.field2和B.field2的比较,
(3)A.field3和B.field3的比较;

变化的部分有两部分,
(1)这三种比较条件的任意组合排列,
(2)升序和降序。

根据这段分析,我们引入两个类,ReverseComparator类和CompositeComparator类。
CompositeComparator类用来解决字段的组合排列问题。
ReverseComparator类用来解决字段的升序、降序问题。

3.3 ReverseComparator类的代码


import java.util.Comparator;

public class ReverseComparator implements Comparator{
/** the original comparator*/
private Comparator originalComparator = null;

/** constructor takes a comparator as parameter */
public ReverseComparator(Comparator comparator){
originalComparator = comparator;
}

/** reverse the result of the original comparator */
public int compare(Object o1, Object o2){
return - originalComparator.compare(o1, o2);
}
}

3.4 CompositeComparator类的代码


import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;

public class CompositeComparator implements Comparator{
/** in the condition list, comparators' priority decrease from head to tail */
private List comparators = new LinkedList();

/** get the comparators, you can manipulate it as need.*/
public List getComparators(){
return comparators;
}

/** add a batch of comparators to the condition list */
public void addComparators(Comparator[] comparatorArray){
if(comparatorArray == null){
return;
}

for(int i = 0; i < comparatorArray.length; i++){
comparators.add(comparatorArray[i]);
}
}

/** compare by the priority */
public int compare(Object o1, Object o2){
for(Iterator iterator = comparators.iterator(); iterator.hasNext();){
Comparator comparator = (Comparator)iterator.next();

int result = comparator.compare(o1, o2);

if(result != 0){
return result;
}
}

return 0;
}
}

3.5 Comparator的组合应用
这一节讲述上面两个类的用法。
对应前面的排序问题,我们只需要3个Comparator类:
(1)Field1Comaprator;
(2)Field2Comaprator;
(3)Field3Comaprator。

下面举例说明,如何组合这些Comparator实现不同的排序条件。
(1)order by field1, field2


CompoiComparator myComparator = new CompoiComparator();
myComparator. addComparators(
new Comparator[]{
new Field1Comaprator (), new Field2Comaprator ()};
);

// records is a list of Record
Collections.sort(records, myComparator);

(1)order by field1 desc, field2

CompoiComparator myComparator = new CompoiComparator();
myComparator. addComparators(
new Comparator[]{
new ReverseComparator(new Field1Comaprator ()),
new Field2Comaprator ()};
);

// records is a list of Record
Collections.sort(records, myComparator);

这里提供的ReverseComparator类和CompositeComparator类都采用了Decorator Pattern。
CompositeComparator类同时也是Composite Pattern。

4.过滤条件的排列组合
过滤条件问题也属于条件组合问题的范畴。比如JDK提供的java.io.File类提供了一个文件过滤方法listFile(FileFilter),用户可以定制不同的FileFilter,实现不同的过滤条件,比如文件时间在某个范围内;文件后缀名,文件名符合某种模式;是目录,还是文件,等等。
同样,我们可以应用上述的解决方法,实现灵活的过滤条件组合――用一个CompositeFilter类任意组合过滤条件,用一个ReverseFilter类作为排除条件。

4.1 CompositeFilter类的代码


import java.io.FileFilter;
import java.io.File;

import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;

public class CompositeFilter implements FileFilter {

/** in the filter list, every condition should be met. */
private List filters = new LinkedList();

/** get the filters, you can manipulate it as need.*/
public List getFilters(){
return filters;
}

/** add a batch of filters to the condition list */
public void addComparators(FileFilter[] filterArray){
if(filterArray == null){
return;
}

for(int i = 0; i < filterArray.length; i++){
filters.add(filterArray[i]);
}
}

/** must meet all the filter condition */
public boolean accept(File pathname) {
for(Iterator iterator = filters.iterator(); iterator.hasNext();){
FileFilter filter = (FileFilter)iterator.next();

boolean result = filter.accept(pathname);

// if any condition can not be met, return false.
if(result == false){
return false;
}
}

// all conditions are met, return true.
return true;
}
}

4.2 ReverseFilter类的代码


import java.util.Comparator;

public class ReverseComparator implements Comparator{
/** the original comparator*/
private Comparator originalComparator = null;

/** constructor takes a comparator as parameter */
public ReverseComparator(Comparator comparator){
originalComparator = comparator;
}

/** reverse the result of the original comparator */
public int compare(Object o1, Object o2){
return - originalComparator.compare(o1, o2);
}
}

做数据库方面还有:DAO模式用的比较的多!

模式有好处,也有坏处如:增加了程序员理解和书写的复杂度,对程序员的要求更高

模式是需要编了相当一段时间的程序,才好理解的

对于初学者:先学习掌握GoF设计模式,再学习UML和Rose,千万别颠倒过来,也别以为使用UML后,可以回避.NET和Java具体代码选择,每个系统的设计方案不是使用UMl就可以完全表达清楚的。

我也希望UML真的如它的名字统一天下语言,早点放弃难学的Java和设计模式。

我觉得学习模式应该注重其解决问题的环境和方法,虽然代码可以帮助我们理解模式的应用方法,但是不应该以此为准,毕竟有些模式是难以用代码表达出来的。不知道我的理解对不对。

除了工厂和单例外,模板和门面模式,策略模式,状态模式,合成模式也是比较多的,我在实践中总结:
1、某些模式解决某些问题是非常有效的
2、不一定非得要使用比较纯的模式
3、模式得精华在于扩展性和复用性,模式的扩展性和复用性思想是主要的,如何使用模式是次要的

还是先理解OO再学模式。
GOF的模式除了Visitor之外,都是比较常用的模式。一些水平比较高的设计人员即使没有学模式,在他们的设计中也会自然的体现模式。

在倚天屠龙记里面,
张三丰教张无忌学习太极剑法,
他演过之后叫张无忌忘记就好。
学习设计模式也是如此,
并不要记得这些招法的形,
而是要领会它的意,
到时候需要用到的时候自然就使出来妙招。

至于UML,
我认为以后应该很可能取代设计模式的,
个人认为现在的企业应用系统开发技术还处于一个很低下的水平,
过3,5年后也许会大变样,
至少可以真正实现搭积木一样地构建系统,
到时候大家关心的也许是任务语义等东西了。

我同意2楼Azure_2003 的看法,模式--我的理解是一些成功经验的实践与抽象的结晶,但不是万能的,对于模式的应用还是要看具体的任务需要,就跟Azure_2003 说的:2、不一定非得要使用比较纯的模式
3、模式得精华在于扩展性和复用性,模式的扩展性和复用性思想是主要的,如何使用模式是次要的

说的太好了, 我绝对赞成!