可扩展的Java应用程序开发模式

上一篇 / 下一篇  2012-08-27 10:45:44 / 个人分类:Java

51Testing软件测试网p"ML0]f!^*~t

  摘要:这个程序最简单的版本是在主类中做每件事情,主类包含一些持有孩子姓名的数组和向量(Vector),一个另一个最简单的方法是为每个孩子创建一个对象,每个对象有一个象isFemal()这样的方法来帮助我们确定要显示的是男的还是女的。51Testing软件测试网*n5]_t$P!p3k

51Testing软件测试网g-a2{j{

   现在很多JAVA书籍,在介绍SWING的事件模型时,为了使JAVA初学者容易理解和上手,通常是在主类(自己的JFrame子类或JPanel)中 做所有事情:要么由主类作为监听器,在接口的方法中通过判定事件源来决定具体做何事;要么在主类中使用内隐类来实现监听器,(因为内隐类可以方便的访问主 类中的成员变量)。而很多JAVA初学者在往后的编程中也采用这种模式(至少我以前是这样的)。其实,这种做法虽然简单,却缺乏可读性、可扩展性和可维护 性。之前我看到了一篇关于这个问题的文章(来自于《JavaPro》),现整理出来与大家分享。51Testing软件测试网{9XSp bMU)pu

4Vi9FZ$m H,k^i}0  下面我将用一个简单的例子来说明如何使用模式来解决这个问题。51Testing软件测试网 GO-?l o:c}c+e

BiZ?}7oo0  现在,假设我们要编写一个使用几个单选按钮从一个长列表中选择不同分组的程序。单击Female单选按钮时,只有女孩的名字被显示;当你点击Male按钮时,程序显示男孩的名字。

c9f+| M }W;gqk051Testing软件测试网AW!|l ]f!|vWF0C

   这个程序最简单的版本是在主类中做每件事情,主类包含一些持有孩子姓名的数组和向量(Vector),一个另一个最简单的方法是为每个孩子创建一个对 象,每个对象有一个象isFemal()这样的方法来帮助我们确定要显示的是男的还是女的。在程序中我们把每个孩子的类称为Swimmer:51Testing软件测试网 ` x(O`(p8bS*`5Hs

public class Swimmer{51Testing软件测试网px'HHq_s5|g7rW
private String name;
~:^A'X^,kxk0private int age;
[#D c,pkQl7} `0private String club;
yDiNE['d0private boolean female;
?/r5[)h%kB0n0public Swimmer(String name,int age,String club,boolean female){
{(@Hy|w0this.name=name;
(I+T'w-u!A)N0this.age=age;51Testing软件测试网_*~%U1q `&H#a;F
this.club=club;
,G#G qV v(?S0Ac0this.female=female;
%^A dJI_U0}51Testing软件测试网T5gNYm;N4g;P$L
public boolean isFemale(){51Testing软件测试网I*m a^^+Y*a0}`+g
return female;
@sx`J#RG/|0}
\ u!J&p4C^3P3q0public String getName(){
B*z6D#B K |0return name;
2b3Z5OCl#y0}51Testing软件测试网:w&u$o]3]'MI
public int getAge(){51Testing软件测试网7i.~z-T:z
return age;51Testing软件测试网1|#}3\w'yJ(F*U,a
}
0|'h(F&T2Ej ^1Q0public String getClub(){
7Q.F S-n!c%xNN D4Gp w0return club;
`2]Z8Rv'| `@ ]Q0}
B4T`L2O+Kx0}

)p1fgOI:V.`;C0  下一步我们要做的是决定整个列表中的哪些孩子会被显示。我们可以在主用户接口类中做到这点,但是最好的是在一个叫做Swimmers的集合类中来做,这个类有一个getList()方法,它带有布尔型的参数来决定是男孩还是女孩:51Testing软件测试网~8[f]X/c&H

//get a vector of swimmers who are (female)
q K] w+On2[|0public Vector getList(boolean female){
9WZ&@#K W:{ T w_0Vector v=new Vector();
q-_L){0R8Oc*E0for(int i=0;i51Testing软件测试网:AYwK-n
Swimmer swm=(Swimmer)kids.elementAt(i);
K!}`E1|+b!v9H$a[6L0if(swm.isFemal()==female) v.add(swm);
6g"QFHr0D0}
UnU-S^|)kxP0return v;
s8oO_cx0}
51Testing软件测试网#ybq5]Xkq%V/VH5`

  我们又提供了一个不带参数的多态getList()方法来返回整个列表。51Testing软件测试网*P2H{.fDL _

51Testing软件测试网T+\+^"D"eO h_vG

  现在让我们进入程序中的第一个重要的部分,为了显示这些孩子的姓名,我们需要为三个单选按钮都添加一个事件监听器,使得每个都能显示出正确的孩子们:

r#S;J:C G!D0public void actionPerformed(ActionEvent e){51Testing软件测试网9j*FR8N:nRm
//listen for button clicks and do the right thing
|5~ ^f u n.]/q0Object bj=e.getSource();
o%G.NqZ@0if(obj==female) loadFemales();51Testing软件测试网?B F+heIr
if(obj==male) loadMales();51Testing软件测试网6uH)u#odc
if(obj==both) loadBoth();
dWF-t6Z&k0}51Testing软件测试网#g?u*xA7VV
private void loadFemales(){
p n R6c]Vl0//display female swimmers51Testing软件测试网R/Fjx6Y
Vector v=swimmers.getList(true);
&O1D1]_6tk0loadList(v);
(a%|IC5F0}51Testing软件测试网G I _]2C s
private void loadMales(){51Testing软件测试网b a| mz2A.P@
//display male swimmers
.s+QF#\i*x'}0Vector v=swimmers.getList(false);51Testing软件测试网1SA1A/}(aD l
loadList(v);
c8D_!LS0}51Testing软件测试网K/D1dnb,Qy
51Testing软件测试网*_vtadI8j

  尽管这个方法在简单、小型的情况下工作得很好,但是它没有良好的可扩展性。如果你有10个按钮,扩展actionPerformed()方法来测试每个按钮和调用某些对应的操作,会使得可读性非常差。相反,我们最好在包含用户接口的类中去掉所有的判定。51Testing软件测试网Q(X;^9R*]

l6a,o.\'O0  做到这点的一个途径是使用Command模式。当我们使用这个模式的时候,需要我们创立一个Command接口:51Testing软件测试网*Z2|lxG*D

;Y~8KLn2|9_051Testing软件测试网?pQ E9\qD

//the Command interface
1z"u|w/N-M)^0public interface Command{51Testing软件测试网CT` L{"?$j
public void execute();51Testing软件测试网rg}J] MJ&Q*@
}

hU Y i g{M M0  我们将三个单选按钮扩展成特定的带有Command接口的类,我们就可以把对命令的执行从JFrame类转移到每个按钮的类。同时,我们创建一 个叫做SexButton的基类,并将ActionListener代码移到基类中,这样就不需要分别在每个按钮中添加事件监听器:

k(E}o!KpR!V051Testing软件测试网 e |2_ Cj

51Testing软件测试网w tbs/e[(VUA!b)r

//abstract radio button class51Testing软件测试网hW'WnkwM
public abstract class SexButton
l%pW:~8t3i'P0extends JRadioButton implements Command{51Testing软件测试网{w'nd6~,Z$vb7z
protected Swimmers simmers;
1ef's7`N2]2X#U_0//JawList is a subclass of JScrollPane contained a JList;51Testing软件测试网1MmMA @i
protected JawList kidList;
+jxlDz%w XNI0public SexButton(String title,Swimmers sw,51Testing软件测试网h6~O1Mf"F7s(vvG L
JawList klist,ActionListener al){
9E3k s.iZ;`0super(title);51Testing软件测试网!I|}h.W,c"b+k{
swimmers=sw;
(T q(aw8z2T |n0kidList=klist;
4^.zzCI m:C,r0addActionListener(al);51Testing软件测试网ov'i(e'FZ"x"w^8w
}51Testing软件测试网5g8~7r%MtH Ov:Hew*H0mn
//abstract execute method51Testing软件测试网3~.Z#h[ ic)n
public abstract void execute();51Testing软件测试网4D2sJ @|%b~ ?0A'w&Z
}

DU8MUu fB8Fm+~0  注意这个类必须被扩展以使得它有用,因为我们没有具体化execute()方法。这个基本的抽象按钮类只是我们从中导出的具体类的一个模板,这实际也是模板设计模式的一个简单例子。

2y"Uv Y!]-S_Lu051Testing软件测试网.?zK7J I b_H

51Testing软件测试网P^~/zd

//radio button to select female swimmers51Testing软件测试网-l6c6q-`T;C
public class FemaleButton extends SexButton{51Testing软件测试网EZ s v*r%EoI
public execute(){51Testing软件测试网T,u CA%vQ!EB
Vector v=swimmers.getList(true);
s-iO;e r6f,\0loadList(v);
fc'H)]z kzU$v7]0}51Testing软件测试网BV8yM,k[2o
private void loadList(Vector v){51Testing软件测试网1rmxMV(N6h
kidList.clear();
7h-y^2F.zs0for(int i=0;i
4Ovw7Ze L%Dw0Swimmer swm=(Swimmer)v.elementAt(i);51Testing软件测试网2Q;Da!x#d ^{G
kidList.add(swm.getName());51Testing软件测试网aM?Qs`w r
}51Testing软件测试网'f-}Pk"Aw
}51Testing软件测试网Kk"k HUCc#D
}
51Testing软件测试网;f%m9M0eZAaJ

  现在,来看一下我们完成的工作。所有的按钮都成为了Command按钮了,actionPerformed()方法也简化成下面这样简单的方法:

|N/i9`U(a;Wb6_:F+W051Testing软件测试网6_j+y.r&z I

51Testing软件测试网c'UO5bG C/m

public void actionPerformed(ActionEvent e){
!fq-k4m&| r ?Q7^`4e0Command cmd=(Command)e.getSource();
F;[s0i/a0cmd.execute();
$[r-Hy7gP"S0}51Testing软件测试网8|2[lzG j

AhZ(\3KH Q#`4b0  正如你看到的,这更加简单而且完全是可扩展的。51Testing软件测试网]"TO_'bQ7Wu3Z

51Testing软件测试网7F'i)JRiF;]y Fi6H

  但我们还有要做的事情。现在我们写了三个单选按钮类,它们知道如何载入一个列表框。在我们匆忙地想要从主类之外得到消息时,我们要求每个按钮都知道列表框。如果我们想要改成一个不同的显示方式,就必须修改这三个类。

S^%Ze,yqO2Zj051Testing软件测试网O~'HV(\\L8gb-Nv

  如果我们在按钮和列表之间创建一个mediator(调停者)类就会好得多,因为它们彼此不需要知道对方。Mediator(调停者)设计模式 能够做到这一点。当一个按钮被点击时,我们创建一个调停者类载入列表。这样所有按钮只知道调停者,哪个列表被载入也只有调停者才知道,当我们想要改成一个 不同的显示方式就只需修改Mediator:

Wx@aQ Y:K-B7d)[051Testing软件测试网7X8re_;|A2\&c$G

51Testing软件测试网s{8`t)EAR[0B

public class Mediator{51Testing软件测试网}5GM0x,Z(b4G0U8Tq
private JawList kidList;51Testing软件测试网_.PY/Rv ^ bU
public Mediator(JawList klist){
$Q W\%T5fV uh0kidList=klist;
/t5k Uw4_ }5p7^+la0}
5M6ZGAyq&Z;l:R0public void loadList(Vector v){
Oxe,H@4G0kidList.clear();
Z(p4VF&@F0for(int i=0;i
;? LcM z a0t@0Swimmer sw=(Swimmer)v.elementAt(i);51Testing软件测试网$r:O ?|)tE_?
kidList.add(sw.getName());
8v8_o"l%E|0}
Jd%s8MP+\3Yw0}51Testing软件测试网(_z5qq np
}
51Testing软件测试网4H"H] |4XPWb

  这样我们的基类变成这样:

k e lc[m_[K051Testing软件测试网'cJpW0Y CR2w o

51Testing软件测试网o fw.s-T0fa&ltQ

public abstract class SexButton
9J t)c!X3GtR0extends JRadioButton implements Command{51Testing软件测试网 ^ NW5{k#o
protected Swimmers swimmers;51Testing软件测试网[fS`hi
protected Mediator med;51Testing软件测试网g+z%j#W,_^"S-H,B3U
public SexButton(String title,Swimmers sw,Mediator md,ActionListener al){
LN^.Y[f0super(title);
T_Sm(A0swimmers=sw;
ivL!O?G?\ c8@ i0med=md;
2b6e)V/f.`yM'{f0[x^0addActionListener(al);51Testing软件测试网 _q bC` KZk]Z
}
U N0~X+] z0public abstract void execute();51Testing软件测试网s"^#yg5qgL
}
51Testing软件测试网ue5{ BV }k

  而FemalButton则变成这样:51Testing软件测试网!cF&d v~GC V

51Testing软件测试网p.\[,|L.\p

51Testing软件测试网:?'k[HT%i

public class FemaleButton extends SexButton{
)Sb$i#n2z9O%C)H I0//use the mediator to load the list51Testing软件测试网(@?'yK.k^:Ri
public void execute(){
2W:SN bJ2j0Vector v=swimmers.getList(true);51Testing软件测试网`,]V8P\
med.loadList(v);51Testing软件测试网4MF}l,Y#ZiZ,]G0n
}
H:Pf^B[O6v6Zk"t*K0}
51Testing软件测试网*@T \"\4Y6bu \

  你看,我们使用Mediator来分离按钮和列表,使它们互相不知道对方。

!M'_ydc'[0

5Xsfm6CC|X0  除了可以使用命令、调停者、模板模式改进这个不到100行的Java代码的简单程序外,还可以使用观察者(Observer)模式。这个程序使用JListData将数据传给列表并从列表中获得数据,并用LawList观察JListData的变化。51Testing软件测试网oG:gvU

51Testing软件测试网UJ;w-?4^(gJ#GJT

,y!?1~'qG A0public class JListData extends AbstractListModel{51Testing软件测试网*w(ngXz^x[
private Vector data;51Testing软件测试网;@{p'C R2Ih
public JListData(){51Testing软件测试网:RSOo$Zw0R x+_
data=new Vector();
2ESC.tO;S+ca.q0}
{qG%{C.N.]-T0public int getSize(){
0aq4Ek a a2`g0return data.size();51Testing软件测试网'L kJ9zvI)t
}51Testing软件测试网}cVlikW8N!g"K
public Object getElementAt(int index){51Testing软件测试网 p1u|!DS
return data.elementAt(index);51Testing软件测试网!qV2QN&KWE
}51Testing软件测试网*Eo"[&?'k oQ;{O
public void addElement(String s){51Testing软件测试网7[y&[ kZ,L&x
data.addElement(s);
%TfD3oNq[)}\9a0fireIntervalAdded(this,data.size()-1,data.size());
9z)W z:n@R0}51Testing软件测试网7R `-ZG,x'ei
public void removeElement(String s){51Testing软件测试网%`Q$D"~ bd-Wp8F9j
data.removeElement(s);
"oc*B G n} g4{G5?pe0fireIntervalRemoved(this,0,data.size());
.odA[~0}51Testing软件测试网F*{0O.u;_l1d
public void clear(){
%q7Y7YQ? `/q z0int size=data.size();
K)}w3\TX4@z2Q;X0data.clear();51Testing软件测试网:~`)|`U:l
fireIntervalRemoved(this,0,size);51Testing软件测试网8x&Af9[B0kE
}
4S1NLhHr*]q0}
-r$?]3s,sLA0public class JawList extends JScrollPane{
5JS"{A+[6q0private JList listwindow;
#q,B%z4r0k(f"p&d0private JListData listContents;
-K,R3\+c%|0public JawList(){
:Y!z"R Z0f8v+I v0listContents=new JList51Testing软件测试网N_/_J@h(S

TAG:

 

评分:0

我来说两句

Open Toolbar