??xml version="1.0" encoding="utf-8" standalone="yes"?>
?Simple Factory 模式Q又叫Static Factory Method.
?Factory Method模式Q又U多态工厂(Polymorphic FactoryQ模式?br />?Abstract Factory模式Q又U工L(fng)QKit或ToolKitQ模式?br />单工厂模式涉?qing)到工厂角色Q抽象品角色以?qing)具体品角色等三个角色Q?br />?工厂c(CreatorQ角Ԍ(x)担Qq个角色的是工厂Ҏ(gu)模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客L(fng)的直接调用下创徏产品对象Q它往往׃个具体的javacd现?br />?抽象产品QProductQ角Ԍ(x)担Qq个角色的是由工厂方法模式所创徏的对象的父类Q或它们共同拥有的接口。抽象品可以由一个Java接口或Java抽象cd现?br />?具体产品QConcrete ProductQ角Ԍ(x)工厂模式所创徏的Q何对象都是这个角色的实例Q具体品角色由一个具体的Javacd现?br />demo:
以农Zؓ(f)例子Q农场公怸门向市场销售水果。农场得有专门的园丁来管理水果?br />interface Fruti
{
//水果的接?br /> /**
* 生长
*/
void grow();
/**
* 收获
*/
void harvest();
/**
* U植
*/
void plant();
}
具体的水?Ҏ(gu)Q葡萄,草莓
Apple.java:
class Apple implements Fruit
{
private int treeAge; //Ҏ(gu)的树(wi)?br />
/**
* 生长
*/
public void grow()
{
log("Apple is growing......");
}
/**
* 收获
*/
pubic void harvest()
{
log("Apple has been harvested.");
}
/**
* U植
*/
public void plant()
{
log("Apple has been planted");
}
/**
* 辅助Ҏ(gu)
*/
public static void log(String str)
{
System.out.println(str);
}
/**
* ?wi)龄的取值方?br /> */
public int getTreeAge()
{
return this.treeAge;
}
/**
* ?wi)龄的赋值方?br /> */
public void setTreeAge(int treeAge)
{
this.treeAge = treeAge;
}
}
Grape.java
class Grape implements Fruit
{
private boolean seedless; //葡萄的籽
/**
* 生长
*/
public void grow()
{
log("Grape is growing.....");
}
/**
* 收获
*/
public void harvest()
{
log("Grape has been harveted");
}
/**
* U植
*/
public void plant()
{
log("Grape has been planted");
}
/**
* 辅助Ҏ(gu)
*/
public static void log(String msg)
{
System.out.println(msg);
}
/**
* 有无c的取值方?br /> */
public boolean getSeedless()
{
return this.seedless;
}
/**
* 有无c的赋值方?br /> */
public void setSeedless(boolean seedless)
{
this.seedless = seedless;
}
}
Strawberry.java
class Strawberry implements Fruit
{
/**
* 生长
*/
public void grow()
{
log("Strawberry is growing.....");
}
/**
* 收获
*/
public void harvest()
{
log("Strawberry has been harvested");
}
/**
* U植
*/
public void plant()
{
log("Strawberry has been planted");
}
/**
* 辅助Ҏ(gu)
*/
public static void log(String msg)
{
System.out.println(msg);
}
}
具体的园?
public class FruitGradener
{
/**
* 静态工厂方?br /> */
public static Fruti factory(String witch)throws BadFruitException
{
if(witch.equalsIgnoreCase("apple"))
{
return new Apple();
}
else if(withc.equalsIgnoreCase("Grape"))
{
return new Grape();
}
else if(witch.equalsIgnoreCase("Strawberry"))
{
return new Strawberry();
}
else
{
thow new BasFruitException("Bad fruit request");
}
}
}
抽象产品角色的主要目的就是给所有的具体产品提供一个共同的cdQ在最单的情况下可以简化ؓ(f)一个标识接口。如:
public interface Product
{
}
工厂c角色就是创Z个新的具体品实例返回给调用者。如:
public class Creator
{
/**
* 静态工厂方?br /> */
return new ConreteProduct();
}
具体的品就是实际的对象了,?
public class ConreteProduct implemnts Product
{
public ConcreteProduct(){}
}
如果模式所产生的具体品类彼此之间没有共同的商业逻辑Q那么抽象品可以由一个JAVA接口扮演Q如果有共同的商务逻辑则应当用抽象角色扮演。这样共同的逻辑都放到抽象类里去了,辑ֈ׃n的目的?img src ="http://www.tkk7.com/antsoul/aggbug/107608.html" width = "1" height = "1" />
]]>
]]>
Generalization(一般化)Q?br />表示cMcM间的l承关系Q接口与接口之间的承关pLcd接口的实现关pR?br />Association(兌)Q?br />cMcM间的q接Q它使一个类知道另一个类的属性和Ҏ(gu)。每个Association都有两个端点Q每个端炚w可以是一个角Ԍ昄出关联的本质。Driver------------>>>>Car.
Aggregation(聚合)Q?br />聚合是一U强烈的兌关系。它整体与个体的关系。区分关联与聚合的关键ؓ(f)逻辑关系?br />Composition(合成)Q?br />兌关系的一U,是比聚合关系q要强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分对象的生命周期,合成关系不能׃n?br />Dependency(依赖)Q?br />cMcM间的q接Q依赖是单向的表CZ个类依赖另一个类的定义?br />
代理模式是比较有用途的一U模?而且变种较多,应用场合覆盖从小l构到整个系l的大结?Proxy是代理的意?我们也许有代理服务器{概?代理概念可以解释?在出发点到目的地之间有一道中间层,意ؓ(f)代理.
设计模式中定?/b>: 为其他对象提供一U代理以控制对这个对象的讉K.
Z么要使用Proxy?
1.授权机制 不同U别的用户对同一对象拥有不同的访问权?如Jive论坛pȝ?׃用Proxyq行授权机制控制,讉K论坛有两Uh:注册用户和游?未注册用?,Jive中就通过cMForumProxyq样的代理来控制q两U用户对论坛的访问权?
2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况:
(1)如果那个对象是一个是很大的图?需要花费很长时间才能显C出?那么当这个图片包含在文档中时,使用~辑器或览器打开q个文档,打开文档必须很迅?不能{待大图片处理完?q时需要做个图片Proxy来代替真正的囄.
(2)如果那个对象在Internet的某个远端服务器?直接操作q个对象因ؓ(f)|络速度原因可能比较?那我们可以先用Proxy来代曉K个对?
M原则?对于开销很大的对?只有在用它时才创徏,q个原则可以为我们节省很多宝늚Java内存. 所?有些为Java耗费资源内存,我以和程序编制思\也有一定的关系.
如何使用Proxy?
?a >Jive论坛pȝZ,讉K论坛pȝ的用h多种cd:注册普通用?论坛理?pȝ理?游客,注册普通用h能发a;论坛理者可以管理他被授权的论坛;pȝ理者可以管理所有事务等,q些权限划分和管理是使用Proxy完成?
Forum是Jive的核心接?在Forum中陈列了有关论坛操作的主要行?如论坛名U?论坛描述的获取和修改,帖子发表删除~辑{?
在ForumPermissions中定义了各种U别权限的用?
public class ForumPermissions implements Cacheable {
/** /** /** /** /** /** /** /** /** ..... public boolean isSystemOrForumAdmin() { ..... } |
因此,Forum中各U操作权限是和ForumPermissions定义的用L(fng)别有关系?作ؓ(f)接口Forum的实?ForumProxy正是这U对应关p联pv?比如,修改Forum的名U?只有论坛理者或pȝ理者可以修?代码如下:
public class ForumProxy implements Forum { private ForumPermissions permissions; public void setName(String name) throws UnauthorizedException, ... } |
而DbForum才是接口Forum的真正实?以修改论坛名UCؓ(f)?
public class DbForum implements Forum, Cacheable { public void setName(String name) throws ForumAlreadyExistsException { ....
} |
凡是涉及(qing)到对论坛名称修改q一事g,其他E序都首先得和ForumProxy打交?由ForumProxy军_是否有权限做某一样事?ForumProxy是个名副其实?|关","安全代理pȝ".
在^时应用中,无可避免总要涉及(qing)到系l的授权或安全体p?不管你有无意识的使用Proxy,实际你已l在使用Proxy?
我们l箋l合Jive谈入׃?下面要涉?qing)到工厂模式?如果你不了解工厂模式,L(fng)我的另外一文?设计模式之Factory
我们已经知道,使用Forum需要通过ForumProxy,Jive中创Z个Forum是用Factory模式,有一个ȝ抽象cForumFactory,在这个抽象类?调用ForumFactory是通过getInstance()Ҏ(gu)实现,q里使用了Singleton(也是设计模式之一,׃介绍文章很多,我就不写?看这?/a>),getInstance()q回的是ForumFactoryProxy.
Z么不q回ForumFactory,而返回ForumFactory的实现ForumFactoryProxy?
原因是明昄,需要通过代理定是否有权限创建forum.
在ForumFactoryProxy中我们看C码如?
public class ForumFactoryProxy extends ForumFactory {
protected ForumFactory factory; public ForumFactoryProxy(Authorization authorization, ForumFactory factory, public Forum createForum(String name, String description) |
Ҏ(gu)createForumq回的也是ForumProxy, Proxyp一道墙,其他E序只能和Proxy交互操作.
注意到这里有两个Proxy:ForumProxy和ForumFactoryProxy. 代表两个不同的职?使用Forum和创建Forum;
至于Z么将使用对象和创建对象分开,q也是ؓ(f)什么用Factory模式的原因所?是ؓ(f)?装" "分派";换句话说,可能功能单一?方便l护修改.
Jive论坛pȝ中其他如帖子的创建和使用,都是按照Forumq个思\而来?
以上我们讨论了如何用Proxyq行授权机制的访?Proxyq可以对用户隐藏另外一U称为copy-on-write的优化方?拯一个庞大而复杂的对象是一个开销很大的操?如果拯q程?没有对原来的对象有所修改,那么q样的拷贝开销没有必?用代理gq这一拯q程.
比如:我们有一个很大的Collection,具体如hashtable,有很多客L(fng)?x)ƈ发同时访问?其中一个特别的客户端要q行q箋的数据获?此时要求其他客户端不能再向hashtable中增加或删除 东东.
最直接的解x案是:使用collection的lock,让这特别的客L(fng)获得q个lock,q行q箋的数据获?然后再释放lock.
public void foFetches(Hashtable ht){
synchronized(ht){
//具体的连l数据获取动?.
}
}
但是q一办法可能锁住Collection?x)很长时?q段旉,其他客户端就不能讉K该Collection?
W二个解x案是cloneq个Collection,然后让连l的数据获取针对clone出来的那个Collection操作.q个Ҏ(gu)前提?q个Collection是可clone?而且必须有提供深度clone的方?Hashtable提供了对自qcloneҎ(gu),但不是Key和value对象的clone,关于Clone含义可以参?a target="_blank">专门文章.
public void foFetches(Hashtable ht){
Hashttable newht=(Hashtable)ht.clone();
}
问题又来?׃是针对clone出来的对象操?如果原来的母体被其他客户端操作修改了, 那么对clone出来的对象操作就没有意义?
最后解x?我们可以{其他客L(fng)修改完成后再q行clone,也就是说,q个特别的客L(fng)先通过调用一个叫clone的方法来q行一pd数据获取操作.但实际上没有真正的进行对象拷?直至有其他客L(fng)修改了这个对象Collection.
使用Proxy实现q个Ҏ(gu).q就是copy-on-write操作.
Proxy应用范围很广,现在行的分布计方式RMI和Corba{都是Proxy模式的应?
更多Proxy应用,?a target="_blank">http://www.research.umbc.edu/~tarr/cs491/lectures/Proxy.pdf
Sun公司?Explore the Dynamic Proxy APIDynamic Proxy Classes
在很多操作中Q比如徏立目?数据库连接都需要这L(fng)单线E操作?/p>
q有, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ(f)一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?/p>
另外斚wQSingleton也能够被无状态化。提供工h质的功能,
Singleton模式׃ؓ(f)我们提供了这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制了实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?br />
我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ(f)被装入的cd际也属于资源?br />
如何使用?
一般Singleton模式通常有几UŞ?
public class Singleton { private Singleton(){} //在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton(); //q里提供了一个供外部讉K本class的静态方法,可以直接讉K
|
W二UŞ?
public class Singleton {
private static Singleton instance = null; }
|
使用Singleton.getInstance()可以讉K单态类?/p>
上面W二中Ş式是lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?/p>
注意到l(f)azy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉?qing)double-checked locking (DCL)的讨论,有兴者进一步研I?/p>
一般认为第一UŞ式要更加安全些?br />
使用Singleton注意事项Q?br />有时在某些情况下Q用Singletonq不能达到Singleton的目的,如有多个Singleton对象同时被不同的c装入器装蝲Q在EJBq样的分布式pȝ中用也要注意这U情况,因ؓ(f)EJB是跨服务器,跨JVM的?/p>
我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocatorZE微分析一下:(x)
在Pet Store中ServiceLocator有两U,一个是EJB目录下;一个是WEB目录下,我们(g)查这两个ServiceLocator?x)发现内容差不多Q都是提供EJB的查询定位服务,可是Z么要分开呢?仔细研究对这两种ServiceLocator才发现区别:(x)在WEB中的ServiceLocator的采取Singleton模式QServiceLocator属于资源定位Q理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用Q所以ServiceLocator才分成两U,一U面向WEB服务的,一U是面向EJB服务的?/p>
Singleton模式看v来简单,使用Ҏ(gu)也很方便Q但是真正用好,是非怸Ҏ(gu)Q需要对Java的类 U程 内存{概忉|相当的了解?/p>
MQ如果你的应用基于容器,那么Singleton模式用或者不用,可以使用相关替代技术?/p>
Z使用?
工厂模式是我们最常用的模式了,著名的Jive论坛 ,大量用了工厂模式Q工厂模式在JavaE序pȝ可以说是随处可见?/span>
Z么工厂模式是如此常用Q因为工厂模式就相当于创建实例对象的newQ我们经常要Ҏ(gu)cClass生成实例对象Q如A a=new A() 工厂模式也是用来创徏实例对象的,所以以后new时就要多个心|是否可以考虑实用工厂模式Q虽然这样做Q可能多做一些工作,但会(x)l你pȝ带来更大的可扩展性和量的修改量?/span>
我们以类SampleZQ?如果我们要创建Sample的实例对?
Sample sample=new Sample();
可是Q实际情冉|Q通常我们都要在创?span lang="EN-US">sample实例时做点初始化的工?比如赋?查询数据库等?/span>
首先Q我们想到的是,可以使用Sample的构造函敎ͼq样生成实例写?
Sample sample=new Sample(参数);
但是Q如果创?span lang="EN-US">sample实例时所做的初始化工作不是象赋DL(fng)单的事,可能是很长一D代码,如果也写入构造函CQ那你的代码很难看了Q就需要Refactor重整Q?/span>
Z么说代码很难看,初学者可能没有这U感觉,我们分析如下Q初始化工作如果是很长一D代码,说明要做的工作很多,很多工作装入一个方法中Q相当于很多鸡蛋放在一个篮子里Q是很危险的Q这也是有背?span lang="EN-US">Java面向对象的原则,面向对象的封?Encapsulation)和分z?Delegation)告诉我们Q尽量将长的代码分派“切剜y成每段Q将每段再“封装”v?减少D和D之间偶合联pL?Q这P׃(x)风险分散,以后如果需要修改,只要更改每段Q不?x)再发生牵一动百的事情?/span>
在本例中Q首先,我们需要将创徏实例的工作与使用实例的工作分开, 也就是说Q让创徏实例所需要的大量初始化工作从Sample的构造函C分离出去?/span>
q时我们需?span lang="EN-US">Factory工厂模式来生成对象了Q不能再用上面简单new Sample(参数)?/span>q有,如果Sample有个l承如MySample, 按照面向接口~程,我们需要将Sample抽象成一个接?现在Sample是接?有两个子cMySample 和HisSample .我们要实例化他们?如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
随着目的深?span lang="EN-US">,Sample可能q会(x)"生出很多儿子出来", 那么我们要对q些儿子一个个实例?更糟p的?可能q要对以前的代码q行修改:加入后来生出儿子的实?q在传统E序中是无法避免?
但如果你一开始就有意识用了工厂模式,q些ȝ(ch)没有了.
工厂Ҏ(gu)
你会(x)建立一个专门生?span lang="EN-US">Sample实例的工?
public class Factory{ public static Sample creator(int which){ //getClass 产生Sample 一般可使用动态类装蝲装入cR?br /> if (which==1) } } |
那么在你的程序中,如果要实例化Sample?׃?/span>
Sample sampleA=Factory.creator(1);
q样,在整个就不涉?qing)到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误.q每个做q具体工作的人都深有体会(x),相反,官做得越?说出的话抽象越W统,范错误可能性就少.好象我们从编E序中也能?zhn)Zh生道?呵呵.
使用工厂Ҏ(gu) 要注意几个角Ԍ首先你要定义产品接口Q如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factoryc,用来生成产品SampleQ如下图Q最双是生产的对象SampleQ?/p>
q一步稍微复杂一点,是在工厂类上进行拓展,工厂cM有承它的实现类concreteFactory?b>?/i>
抽象工厂
工厂模式中有: 工厂Ҏ(gu)(Factory Method) 抽象工厂(Abstract Factory).
q两个模式区别在于需要创建对象的复杂E度上。如果我们创建对象的Ҏ(gu)变得复杂?如上面工厂方法中是创Z个对象Sample,如果我们q有新的产品接口Sample2.
q里假设QSample有两个concretecSampleA和SamleBQ而Sample2也有两个concretecSample2A和SampleB2
那么Q我们就上例中Factory变成抽象c?共同部分封装在抽象cM,不同部分使用子类实现Q下面就是将上例中的Factory拓展成抽象工?
public abstract class Factory{ public abstract Sample creator(); public abstract Sample2 creator(String name); } public class SimpleFactory extends Factory{ public Sample creator(){ public Sample2 creator(String name){ } public class BombFactory extends Factory{ public Sample creator(){ public Sample2 creator(String name){ }
|
从上面看C个工厂各自生产出一套Sample和Sample2,也许你会(x)疑问Qؓ(f)什么我不可以用两个工厂方法来分别生Sample和Sample2?
抽象工厂q有另外一个关键要点,是因?SimpleFactory内,生Sample和生产Sample2的方法之间有一定联p,所以才要将q两个方法捆l在一个类中,q个工厂cL其本w特征,也许刉过E是l一的,比如Q制造工艺比较简单,所以名U叫SimpleFactory?/span>
在实际应用中Q工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
举例
我们?span lang="EN-US">Jive的ForumFactoryZQ这个例子在前面的Singleton模式中我们讨Q现在再讨论其工厂模?
public abstract class ForumFactory { private static Object initLock = new Object(); public static ForumFactory getInstance(Authorization authorization) { try { //Now, q回 proxy.用来限制授权对forum的访?br /> return new ForumFactoryProxy(authorization, factory, //真正创徏forum的方法由l承forumfactory的子cd完成. .... }
|
因ؓ(f)现在?span lang="EN-US">Jive是通过数据库系l存放论坛帖子等内容数据,如果希望更改为通过文gpȝ实现,q个工厂Ҏ(gu)ForumFactory提供了提供动态接?
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以用自己开发的创徏forum的方法代替com.jivesoftware.forum.database.DbForumFactory可?
在上面的一D代码中一q了三U模?span lang="EN-US">,除了工厂模式?q有Singleton单态模?以及(qing)proxy模式,proxy模式主要用来授权用户对forum的访?因ؓ(f)讉Kforum有两Uh:一个是注册用户 一个是游客guest,那么那么相应的权限就不一?而且q个权限是诏I整个系l的,因此建立一个proxy,cM|关的概?可以很好的达到这个效?
看看Java宠物店中的CatalogDAOFactory:
public class CatalogDAOFactory {
/** * 本方法制定一个特别的子类来实现DAO模式?br /> * 具体子类定义是在J2EE的部|描q器中?br /> */ public static CatalogDAO getDAO() throws CatalogDAOSysException { CatalogDAO catDao = null; try { InitialContext ic = new InitialContext(); String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS); catDao = (CatalogDAO) Class.forName(className).newInstance(); } catch (NamingException ne) { throw new CatalogDAOSysException(" } catch (Exception se) { throw new CatalogDAOSysException(" } return catDao; } } |
CatalogDAOFactory是典型的工厂Ҏ(gu)QcatDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类Q这个实现子cdJava宠物店是用来操作catalog数据库,用户可以Ҏ(gu)数据库的cd不同Q定制自q具体实现子类Q将自己的子cdl与CATALOG_DAO_CLASS变量可以?/span>
由此可见Q工厂方法确实ؓ(f)pȝl构提供了非常灵zd大的动态扩展机Ӟ只要我们更换一下具体的工厂Ҏ(gu)Q系l其他地Ҏ(gu)需一点变换,有可能系l功能进行改头换面的变化?/p>
J2EE可以说指Java在数据库信息pȝ上实玎ͼ数据库信息系l从早期的dBase、到Delphi/VB{C/Sl构Q发展到B/SQBrowser览?Server服务器)(j)l构Q而J2EE主要是指B/Sl构的实现?/p>
J2EE又是一U框架和标准Q框架类似API、库的概念,但是要超出它们。如果需要详l了解框Ӟ可先从设计模式开始学?fn)?/p>
J2EE是一个虚的大的概念,J2EE标准主要有三U子技术标准:(x)WEB技术、EJB技术和JMSQ谈到J2EE应该说最l要落实到这三个子概念上?/p>
q三U技术的每个技术在应用旉涉及(qing)两个部分Q容器部分和应用部分QW(xu)eb容器也是指Jsp/Servlet容器Q你如果要开发一个Web应用Q无论是~译或运行,都必要有Jsp/Servlet库或API支持Q除了JDK/J2SE以外Q?/p>
Web技术中除了Jsp/Servlet技术外Q还需要JavaBeans或Java Class实现一些功能或者包装携带数据,所以Web技术最初裸体简UCؓ(f)Jsp/Servlet+JavaBeanspȝ?/p>
谈到JavaBeans技术,涉?qing)到lg构g技术(componentQ,q是Java的核心基部分Q很多Y件设计概念(设计模式Q都是通过JavaBeans实现的?/p>
JavaBeans不属于J2EE概念范畴中,如果一个JavaBeans对象被Web技术(也就是Jsp/ServletQ调用,那么JavaBeansp行在J2EE的Web容器中;如果它被EJB调用Q它?yu)p行在EJB容器中?/p>
EJBQ企业JavaBeansQ是普通JavaBeans的一U提升和规范Q因Z业信息系l开发中需要一个可伸羃的性能和事务、安全机Ӟq样能保证企业系l^滑发展,而不是发展到一U规模重新更换一套Y件系l?/p>
xQJavaBeanslg发展到EJB后,q不是说以前的那UJavaBeans形式消׃Q这p然Ş成了两种JavaBeans技术:(x)EJB和POJOQPOJO完全不同于EJB概念Q指的是普通JavaBeansQ而且q个JavaBeans不依附某U框Ӟ或者干脆可以说Q这个JavaBeans是你个应用程序单独开发创建的?/p>
J2EE应用pȝ开发工h很多Q如JBuilder、Eclipse{,q些IDE首先是Java开发工P也就是说Q它们首要基本功能是可以开发出JavaBeans或Java classQ但是如果要开发出J2EEpȝQ就要落实到要么是Web技术或EJB技术,那么有可能要一些专门模块功?如eclipse需要lomboz插g)Q最重要的是Q因为J2EEpȝ区分为容器和应用两个部分Q所以,在Q何开发工具中开发J2EE都需要指定J2EE容器?/p>
J2EE容器分ؓ(f)WEB容器和EJB容器QTomcat/Resin是Web容器QJBoss是EJB容器+Web容器{,其中Web容器直接使用Tomcat实现的。所以你开发的Web应用E序可以在上面两U容器运行,而你开发的Web+EJB应用则只可以在JBoss服务器上q行Q商业品Websphere/Weblogic{和JBoss属于同一U性质?/p>
J2EE容器也称为J2EE服务器,大部分时它们概念是一致的?/p>
如果你的J2EE应用pȝ的数据库q接是通过JNDI获得Q也是说是从容器中获得Q那么你的J2EE应用pȝ基本与数据库无关Q如果你在你的J2EE应用pȝ耦合了数据库JDBC驱动的配|,那么你的J2EE应用pȝ有数据库概念色彩,作ؓ(f)一个成熟需要推q的J2EE应用pȝQ不推荐和具体数据库耦合Q当然这其中如何保证J2EE应用pȝq行性能又是体现你的设计水^了?/p>
衡量J2EE应用pȝ设计开发水q高低的标准是Q解耦性;你的应用pȝ各个功能是否能够dqQ是否不怺依赖Q也只有q样Q才能体现可l护性、可拓展性的软g设计目标?/p>
Z辑ֈq个目的Q诞生各U框架概念,J2EE框架标准一个系l划分ؓ(f)WEB和EJB主要部分Q当然我们有时不是以q个具体技术区分,而是从设计上抽象现层、服务层和持久层Q这三个层次从一个高度将J2EE分离开来,实现解耦目的?/p>
因此Q我们实际编E中Q也要将自己的功能向q三个层ơ上靠,做到大方向清楚,泾渭分明Q但是没有技术上U束限制要做到这Ҏ(gu)很不Ҏ(gu)的,因此我们q是必须借助J2EE具体技术来实现Q这Ӟ你可以用EJB规范实现服务层和持久层,W(xu)eb技术实现表现层Q?/p>
EJBZ么能服务层从Jsp/Servlet手中分离出来Q因为它对JavaBeans~码有强制的U束Q现在有一U对JavaBeansq束,使用Ioc模式实现的(当然EJB 3.0也采取这U方式)(j)Q在Ioc模式诞生前,一般都是通过工厂模式来对JavaBeansU束QŞ成一个服务层Q这也是是Jiveq样开源论坛设计原理之一?/p>
由此Q将服务层从表现层中分离出来目前有两U可选架构选择Q管理普通JavaBeansQPOJOQ框?如Spring?a target="_blank">JdonFramework)以及(qing)理EJB的EJB框架Q因为EJB不只是框Ӟq是标准Q而标准可以扩展发展,所以,q两U区别将来是可能模糊Q被U_同一个标准了。 但是Q个为:(x)标准制定是ؓ(f)某个目的服务的,总要牺牲一些换取另外一些,所以,q两U架构会(x)长时间ƈ存?/p>
q两U架构分歧也曄诞生一个新名词Q完全POJO的系l也UCؓ(f)轻量U系l?lightweight)Q其实这个名词本w就没有一个严格定义,更多是一个吸引h的招牌,轻量是指Ҏ(gu)学习(fn)Ҏ(gu)使用吗?按照q个定义Q其实轻量Spring{系lƈ不容易学?fn);而且EJB 3.0Q依然叫EJBQ以后的pȝ是否可称量了呢Q?/p>
前面谈了服务层框Ӟ使用服务层框架可以将JavaBeans从Jsp/Servlet中分d来,而用表现层框架则可以将Jsp中剩余的JavaBeans完全分离Q这部分JavaBeans主要负责昄相关Q一般是通过标签库(taglibQ实玎ͼ不同框架有不同自q标签库,Struts是应用比较广泛的一U表现层框架?/p>
q样Q表现层和服务层的分L通过两种框架辑ֈ目的Q剩余的是持久层框架了Q通过持久层的框架数据库存储从服务层中分d来是其目的,持久层框架有两种方向Q直接自q写JDBC{SQL语句Q如iBatisQ;使用O/R Mapping技术实现的Hibernate和JDO技术;当然q有EJB中的实体Bean技术?/p>
持久层框架目前呈现百花齐放,各有优缺点的现状Q所以正如表现层框架一P目前没有一个框架被指定为标准框Ӟ当然Q表现层框架现在又出来了一个JSFQ它代表的页面组件概忉|一个新的发展方向,但是复杂的实现让人有些忘而却步?/p>
在所有这些J2EE技术中Q虽然SUN公司发挥了很大的作用Q不qM来说Q网l上有这样一个评P(x)SUN的理论天下无敌;SUN的品用h撞墙Q对于初学者,特别是那些试N过或已l通过SUN认证的初学者,赶快摆脱SUN的阴影,立即开溜,使用开源领域的产品来实现自q应用pȝ?/p>
最后,你的J2EE应用pȝ如果采取上面提到的表现层、服务层和持久层的框架实玎ͼ基本你也可以在无需深刻掌握设计模式的情况下开发出一个高质量的应用系l了?/p>
q要注意的是: 开发出一个高质量的J2EEpȝq需要正的业务需求理解,那么域徏模提供了一U比较切实可行的正确理解业务需求的Ҏ(gu)Q相兌l知识可从UML角度l合理解?/p>
当然Q如果你惌计自q行业框架Q那么第一步从设计模式开始吧Q因计模式提供你一个实现JavaBeans或类之间解耦参考实现方法,当你学会(x)了系l基本单元JavaBean或类之间解耦时Q那么系l模块之间的解耦你可能掌握,q而你可以实现行业框架的提炼了,q又是另外一个发展方向了?/p>
以上理念可以ȝZ句话Q?br />J2EE开发三件宝: Domain ModelQ域建模Q、patternsQ模式)(j)和frameworkQ框Ӟ(j)?/p>
传统思维?fn)惯分?/font>
Z么会(x)业务逻辑层用if elseQ其实用者的目的也是Z重用Q但是这是面向过E编E的重用Q程序员只看C码重用,因ؓ(f)他看到if else几种情况下大部分代码都是重复的,只有个别不同Q因此用if else可以避免重复代码Qƈ且认是模板Template模式?/font>
他范的错误是Q程序员只从代码q行序q个方向来看待它的代码,q种思维cM水管或串行电(sh)路,水沿着水管动Q代码运行次序)(j)Q当遇到几个分管Q子)(j)Q就分到q几个分子在流动,q里q当于到代码的if else处了?/font>
而用OOQ则首先打破q个代码׃向下序{同于运行时的先后@序这个规律,代码l构不由执行循序军_Q由什么决定呢Q由O(jin)O设计Q设计模式会(x)取代q些if elseQ但是最后L׃个Service{ȝ按照q行序l装q些OO模块Q只有一处,q处可包含事务,一般就是ServiceQEJB中是Session bean?/font>
一旦需求变化,我们更多的可能是Service中各个OO模块Q甚x只改动Service中的OO模块执行序pW合需求?/font>
q里我们也看到OO分离的思\Q将以前q程语言的一个Main函数d分解Q将q行序与代码其他逻辑分离开来,而不是象面向q程那样混ؕ在一赗所以有人感慨,OO也是要顺序的Q这是肯定的Q关键是q行序要单独分d来?/font>
是否有if else可以看出你有没有运行顺序分d家?/font>
设计模式的切入口
l常有h反映Q设计模式是不错Q但是我很难用到Q其实如果你使用if else来写代码Ӟ除显C控制以外)(j)Q就是在写业务逻辑Q只不过使用单的判断语句来作为现实情늚替代者?/font>
q是以大家熟(zhn)的论坛帖子Z子,如ForumMessage是一个模型,但是实际中帖子分两种性质Q主题脓(chung)Q第一个根_(d)(j)和回帖(回以前帖子的帖子Q,q里有一个朴素的解决Ҏ(gu)Q?br />建立一个ForumMessageQ然后在ForumMessage加入isTopicq样判断语句Q注意,你这里一个简单属性的判断引入Q可能导致你的程序其他地方到处存在if else 的判断?/font>
如果我们改用另外一U分析实现思\Q以对象化概늜待,实际中有主题贴和回帖Q就是两U对象,但是q两U对象大部分是一致的Q因此,我将ForumMessage设ؓ(f)表达主题_(d)然后创徏一个承ForumMessage的子cForumMessageReply作ؓ(f)回帖Q这P我在E序地方Q如Service中,我已l确定这个Model是回帖了Q我q接下溯ؓ(f)ForumMessageReply卛_Q这个有点类似向Collection攑օ对象和取出时的强制类型{换。通过q个手段我消灭了以后E序中if else的判断语句出现可能?/font>
从这里体CQ如果分析方向错误,也会(x)D误用模式?/font>
讨论设计模式举例Q不能没有业务上下文场景的案例,否则无法军_是否该用模式Q下面D两个Ҏ(gu)的例子:(x)
W一. q个帖子 中D例的W一个代码案例是没有上下文的Q文中只说明有一D代码:(x)
main() {
ifQcase AQ{ //do with strategy A }else(case B){ //do with strategy B }else(case C){ //do with strategy C } } |
q段代码只是Ua(b)的代码,没有业务功能Q所以,在这U情况下Q我们就很难定使用什么模式,是一定用{略模式{,也逃不q还是用if else的命q,设计模式不是法Q不能将一D|无意义的代码变得单了Q只能将其体现的业务功能更加Ҏ(gu)可拓展了?/font>
W二.?/font> q个帖子 中,作者D了一个PacketParser业务案例Q这D代码是体现业务功能的,是一个数据包的分析,作者也比较了各U模式用的不同Q所以我们还是用动态代理模式或Command模式来消灭那些可能存在的if else
׃上两个案例表明:(x)业务逻辑是我们用设计模式的切入点,而在分解业务逻辑Ӟ我们?fn)惯则可能用if else来实玎ͼ当你有这U企图或者已l实C码了Q那么就应该考虑是否需要重构Refactoring了?br />
if else替代?/font>
那么实战中,哪些设计模式可以替代if else呢?其实GoF设计模式都可以用来替代if elseQ我们分别描q如下:(x)
public class Order{ private int status; //说明Q? //status=1 表示订货但ؓ(f)查看 Q?/font> //status=2 表示已经查看未处理; //status=3 表示已经处理未付?gu)?/font> //status=4 表示已经付款未发?/font> //status=5 表示已经发货 } |
OO设计的ȝ
q有一U伪模式Q虽然用了状态等模式Q但是在模式内部实质q是使用if else或switchq行状态切换或重要条g判断Q那么无疑说明还需要进一步努力。更重要的是Q不能以模式自居Q而且ZCZh?/font>
真正掌握面向对象q些思想是一件困隄事情Q目前有各种属于揪着自己头发向上拔的解说Q都是误人子弟的Q所以我觉得初学者读Thinking in JavaQJava~程思想Q是没有用,它试图从语言层次来讲OO~程思想Q非常失败,作ؓ(f)语言参考书可以Q但是作为Java体现的OO思想的学?fn)资料,错了?/font>
OO~程思想是一U方法论Q方法论如果没有应用比较Q是无法体会(x)q个Ҏ(gu)论的特点的,是古代一个方法论Q?zhn)是靠挑水砍柴这些应用才能体会(x)?/font>
那么OO思想靠什么应用能够体?x)到了?是GoF设计模式QGoF设计模式是等于Y件h员的挑水砍柴{基本活Q所以,如果一个程序员q基本活都不?x),他何以自居OOE序员?从事OO专业设计~程q个工作Q如果不掌握设计模式基本功,p一个做和尚的h不愿意挑水砍_(d)他何以立个行业?早就被师傅赶下山?/font>
最后ȝQ将if else用在地方还可以Q如单的数值判断;但是如果按照你的传统?fn)惯思维Q在实现业务功能时也使用if elseQ那么说明你的思维可能需要重塑,你的~程l验丰富,传统q程思维模式容易根p固,想靠自己改变很困难;接受 专业头脑风暴培训 ?/font>
用一句话ȝQ如果你做了不少pȝQ很久没有用if else了,那么说明你可能真正进入OO设计的境C。(q是本h自己发明的实战性的衡量考核标准Q?/font>
为此Q我们通过一个通俗而有的CZQ这个示例是设计一个猎人,其持有一把智能猎枪,q就是说q把猎枪?x)自动识别hc,若发现瞄准的目标是hc,׃?x)开火,而其它的M事物都通杀?br /> 为此Q我们用了下面三个接口Q?br />
一个用来表CZ事万物的SomeThing
public interface SomeThing {}
人类的接口:(x)
public interface Humans extends SomeThing {}
动物的接口:(x)
public interface Animals extends SomeThing {}
然后是一pd的实玎ͼ(x)
中国人:(x)
public class Chinese implements Humans {}
日本人:(x)
public class Japanese {}
狗:(x)
public class Dog implements Animals {}
妖?他很聪明,l自己帖上了人的标签)Q?br />public class Monster implements Humans {}
下面q个E序的核心部分,
猎hcd(qing)客户端程序:(x)
public class Hunter {
public void fire(Object target)
{
if(target instanceof Humans)
{
System.out.println("q下完了Q打中了一个hQ该d牢了Q?);
}
else
{
System.out.println("恭喜你,打中了一只动?");
}
}
//的枪
public void intelligentFire(Object target)
{
if(target instanceof Humans)
{
return;
}
System.out.println("开了一?"+target.getClass());
//下面q行U杀{相兛_?br /> //销毁他
target=null;
}
public static void main(String[] args) {
Hunter hunter=new Hunter();
Object[] objects=new Object[]{new Dog(),new Japanese(),new Japanese(),new Chinese(),new Monster(),new SomeThing(){}};
for(int i=0;i<objects.length;i++)
hunter.intelligentFire(objects[i]);
}
}
q行E序Q你?x)发现输出类g面结果:(x)
开了一?class springroad.demo.taginterface.Dog
开了一?class springroad.demo.taginterface.Japanese
开了一?class springroad.demo.taginterface.Japanese
开了一?class springroad.demo.taginterface.Hunter$1
由此可见Q智能猎枪瞄?个目标,开?枪。只对Chinese、及(qing)Monster的实例没有开枪。因里讨论的是标{接口,虽然Humans没有MҎ(gu)Q但从智能猎枪的角度来看Q他是通过q个标签来判断是否可以开火的?/font> 他不用管也管不了目标的层ơ等U关p(比如Japanese肯定很非帔R明等U结?Q即l承关系。他也管不了目标的来自于哪儿。比如,是用new操作W创建,q是从容器中取,或者是从网l某个地方加载一个?br /> Hunter只是制订了一个简单的规则Q你要想不让我的枪对你开火,你就必须在自pn上帖上一个Humans的标{。也是说你必须遵守q个规则?br /> 现在回过头来看,因ؓ(f)妖怪Monster真n应该是一条蛇或其它什么动物,但是他懂得Hunter制订的规则,于在巧妙的给自己帖上了一个Humans的标{,以致于欺骗了我们的智能猎枪?br /> 而Japanese则自认ؓ(f)自己了不P不按规则办事Q我׃理你Hunter制订的规则,什么Humans标签Q我是不用。于是放到我们的E序中当然就只有挨杀的䆾了?/font>
由此可见Q空接口(标签接口)的重要性,在像本例中,l不l自己帖不标{,q是一个性命莜关的问题。其实在OO的世界中Q空接口可以是最高的层像?/strong>
class Student implements Cloneable
{
Professior p;
String name;
int age;
public Student(String name,int age,Professior p)
{
this.name =name;
this.age = age;
this.p = p;
}
public Object clone()
{
Object o = null;
try
{
o=super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
return o;
}
public String toString()
{
return "name="+name+","+"age="+age;
}
}
class Professior
{
String name;
int age;
public Professior(String name,int age)
{
this.name = name;
this.age = age;
}
}
Result:
D:\jcode>java StringTest
s1.p.name=lisi,s1.p.age=20
通过l果看得Z个问题,当我们修改s2的Professior后,s1对象的Professior对象的D修改了。不是有clone?份copy吗?那怎么修改S1的值却影响了S2的gQ那是因为我们克隆的时候只是把Professior的引用复制了一份,而ƈ没有实际在内存中l它分配C块内存,所以我们clone的时候,其实是把同一个值给复制?ơ,所以s1和s2操作的professior都是同一个对象,所以修改S1Q必然就影响了S2的professior的|那我们的本意q如此Q有没有办法解决呢?{案是肯定的。其实我们刚才所做的操作是一个浅克隆Q当我们克隆的对象是引用cd的时候,可以用深克隆来实现。就如下面的Demo.
class CloneTest
{
public static void main(String[] args)
{
Boss boss = new Boss("antsoul",25);
Leader leader = new Leader("linda",30);
Employee ep1 = new Employee("zhangsan",107,leader,boss);
Employee ep2 = (Employee)ep1.clone();
ep2.boss.name = "gll";
ep2.boss.age = 60;
System.out.println("ep1.leader.name="+ep1.boss.name);
System.out.println("ep1.leader.age="+ep1.boss.age);
}
}
class Employee implements Cloneable
{
String name;
int eid;
Leader leader;
Boss boss;
Employee(String name,int eid,Leader leader,Boss boss)
{
this.name = name;
this.eid = eid;
this.leader = leader;
this.boss = boss;
}
public Object clone()
{
Employee o = null;
try
{
o = (Employee)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
o.leader = (Leader)leader.clone();
o.boss = (Boss)boss.clone();
return o;
}
}
class Leader implements Cloneable
{
String name;
int age;
Leader(String name,int age)
{
this.name = name;
this.age = age;
}
public Object clone()
{
Object o = null;
try
{
o = super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
return o;
}
}
class Boss implements Cloneable
{
String name;
int age;
Boss(String name,int age)
{
this.name = name;
this.age = age;
}
public Object clone()
{
Object o = null;
try
{
o = super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.getMessage());
}
return o;
}
}
q里有个疑问了,Z么我们要在派生类中over writte Object的clone()Ҏ(gu)Ӟ一定要调用super.clone()?
原因? 在运行时刻,Object中的clone()识别Z要clone的是哪一个对象,然后为此对象分配内存I间Qƈq行对象的复Ӟ原始对象的内容一一复制到新的对象空间中厅R?/font>
class TreeSetTest
{
public static void main(String[] args){
TreeSet ts = new TreeSet();
ts.add(new Student("one",1));
ts.add(new Student("two",4));
ts.add(new Student("three",3));
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Student implements Comparable
{
private String name;
private int num;
//Z调用方便声明为static
static class StudentComparator implements Comparator
{
public int compare(Object o1,Object o2){
Student s1 =(Student)o1;
Student s2 =(Student)o2;
int result;
result = s1.num > s2.num ? 1 :(s1.num==s2.num ? 0 : -1);
if(result == 0){ //student的num相同Q比较name,因ؓ(f)name为StringcdQ它实现了Comparable<String>
result = s1.name.compareTo(s2.name);
}
return result;
}
}
public Student(String name,int num){
this.name = name;
this.num = num;
}
public int compareTo(Object o){
Student s =(Student)o;
return num > s.num ? 1 : (num == s.num ? 0 : -1);
}
public String toString(){
return "num="+num+" "+"name="+name;
}
}
class MyQueen
{
private LinkedList aa = new LinkedList();
public void put(Object o){
//d元素
aa.addLast(o);
}
public Object get(){
//获得元素
return aa.removeFirst();
}
public boolean empty(){
return aa.isEmpty();
}
public static void main(String[] args){
MyQueen mq = new MyQueen();
mq.put("one");
mq.put("two");
mq.put("three");
System.out.println(mq.get());
System.out.println(mq.empty());
}
}
] ArrayList ?LinkedList
a. ArrayList底层采用数组完成Q而LinkedList则是以一般的双向链表(double-linked list)完成Q其内每个对象,除了数据本n外,q有两个引用Q分别指向前一个元素和后一个元素?br />b. 如果我们l常在List的开始处增加元素,或则在List中进行插入和删除操作Q我们应该用LinkedListQ否则的话,使用ArrayList则更快?br />
HashSet
1. 实现Set接口的hash table,依靠HashMap来实现?br />2. 应该为存攑ֈ散列表中的各个对象定义hashCode()和equals()?br />3. 散列表又U哈希表。散列表法的基本思想:
以节点的关键字ؓ(f)自变量,通过一定的函数关系(散列函数)计算出对应的函数|以这个g节点存储在散列表中的地址?br />4. 当散列表中元素存攑֤满,必d散列Q将产生一个新的散列表,所有元素存攑ֈ新的散列表中,原先的散列表被删除。Jaav语言中,通过负蝲因子(load factor)来决定何时对散列表再q行散列。例如:(x)如果负蝲因子?.75,当散列表中有75%被存满,进行再散列?br />5. 负蝲因子高(?.0近)Q内存的使用效率高,元素的寻找时间越ѝ负载因子越?接q?.0),元素的寻找时间越短,内存?gu)费多?br />6. HashSet的缺省因子是0.75?br />
HashSet demo:
import java.util.*;
class HashSetTest
{
public static void main(String[] args){
HashSet hs = new HashSet();
hs.add(new Student("zhangsan",1));
hs.add(new Student("lisi",2));
hs.add(new Student("wangwu",3));
hs.add(new Student("zhangsan",1));
Iterator it = hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Student
{
String name;
int num;
public Student(String name,int num){
this.name = name;
this.num = num;
}
public int hashCode(){
return num * name.hashCode();
}
public boolean equals(Object o){
Student s =(Student)o;
return num==s.num && name.equals(s.name);
}
public String toString(){
return num+":"+name;
}
}
class ArrayListTest
{
public static void printElements(Collection c){
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args){
Student s1 = new Student("antsoul",25);
Student s2 = new Student("feiyang",35);
Student s3 = new Student("gll",24);
Student s4 = new Student("andylau",40);
ArrayList al = new ArrayList();
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);
Collections.sort(al);
printElements(al);
}
}
class Point
{
int x,y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
public String toString(){
return ("x="+x+","+"y="+y);
}
}
class Student implements Comparable
{
private String name;
private int num;
public Student(String name,int num){
this.name = name;
this.num = num;
}
public int compareTo(Object o){
Student s =(Student)o;
return num > s.num ? 1 : (num == s.num ? 0 : -1);
}
public String toString(){
return "num:"+num+" "+"name:"+name;
}
}
?比较器L和特定的cȝ关的Q具体到某一个类。比如说对student排序Q你要用到学P所以排序前必须要{换Object为Student,也就是ؓ(f)某一个类指定一个比较器Q可以写一个类d现比较器的接口,但是Z联系紧密Q可以在q里用内部类在实现比机器接口?br />import java.util.*;
class ArrayListTest
{
public static void printElements(Collection c){
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args){
Student s1 = new Student("antsoul",2);
Student s2 = new Student("feiyang",1);
Student s3 = new Student("gll",3);
Student s4 = new Student("andylau",4);
ArrayList al = new ArrayList();
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);
Collections.sort(al,new Student.StudentComparator()); //student提供自己的比较器
printElements(al);
}
}
class Point
{
int x,y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
public String toString(){
return ("x="+x+","+"y="+y);
}
}
class Student implements Comparable
{
private String name;
private int num;
//Z调用方便声明为static
static class StudentComparator implements Comparator
{
public int compare(Object o1,Object o2){
Student s1 =(Student)o1;
Student s2 =(Student)o2;
return s1.num > s2.num ? 1 :(s1.num==s2.num ? 0 : -1);
}
}
public Student(String name,int num){
this.name = name;
this.num = num;
}
public int compareTo(Object o){
Student s =(Student)o;
return num > s.num ? 1 : (num == s.num ? 0 : -1);
}
public String toString(){
return "num:"+num+" "+"name:"+name;
}
}
如果student的num相等的情况下Q要以name来排序可以这样实?
import java.util.*;
class ArrayListTest
{
public static void printElements(Collection c){
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args){
Student s1 = new Student("antsoul",2);
Student s2 = new Student("feiyang",1);
Student s3 = new Student("dorydoo",3);
Student s4 = new Student("sun",4);
Student s5 = new Student("gll",4);
ArrayList al = new ArrayList();
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);
al.add(s5);
Collections.sort(al,new Student.StudentComparator()); //student提供自己的比较器
printElements(al);
}
}
class Point
{
int x,y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
public String toString(){
return ("x="+x+","+"y="+y);
}
}
class Student implements Comparable
{
private String name;
private int num;
//Z调用方便声明为static
static class StudentComparator implements Comparator
{
public int compare(Object o1,Object o2){
Student s1 =(Student)o1;
Student s2 =(Student)o2;
int result;
result = s1.num > s2.num ? 1 :(s1.num==s2.num ? 0 : -1);
if(result == 0){ //student的num相同Q比较name,因ؓ(f)name为StringcdQ它实现了Comparable<String>
result = s1.name.compareTo(s2.name);
}
return result;
}
}
public Student(String name,int num){
this.name = name;
this.num = num;
}
public int compareTo(Object o){
Student s =(Student)o;
return num > s.num ? 1 : (num == s.num ? 0 : -1);
}
public String toString(){
return "num="+num+" "+"name="+name;
}
}
D:\jcode>java Exchange
x=3
y=2