您的位置:首页 > 其它

九种常用设计模式的简单应用

2014-05-12 09:59 363 查看
什么是设计模式

一、工厂方法模式(FactoryMethodPattern)

1、1适用于以下情况

1、2类图

1、3实例:工厂方法模式之多数据库链接的实现

1、4优缺点

二、单例模式(SingletonPattern)

2、1适用于以下情况

2、2类图

2、3实例

三、值对象模式(valueobject)

3、1适用于以下情况

3、2类图

3、3实例

3、4优势

四、DAO模式(DataAccessObject)

4、1DAO的功能

4、2类图

4、3实例

4、4优劣势

五、门面模式(Facade)

5、1适用情况

5、2类图

5、3实例

六、装饰模式(Decorator)

6、1装饰模式的特点

6、2类图

6、3实例

七、适配器模式(Adapter)

7、1适用以下情况

7、2类图

7、3实例

八、责任链模式(ChainofResponsibility)

8、1类图

8、2实例

8、3总结

九、建造者模式(BuilderPattern)

9、1适用情况

9、2类图

9、3实例

什么是设计模式

在面向对象的软件设计中,总是希望避免重复设计或尽可能少做重复设计。有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总是求助于以前使用过的非面向对象技术。有经验的设计者显然知道一些新手所不知道的东西,这又是什么呢?内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用过的解决方案。

当找到一个好的解决方案,他们会一遍又一遍地使用。这些经验是他们成为内行的部分原因。它们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。一个熟悉这些模式的设计者不需要再去发现它们,而能够立即将它们应用于设计问题中。

设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统复用的选择,避免设计损害了系统复用性。通过提供一个显式类和对象作用关系以及它们之间潜在联系的说明规范,设计模式甚至能够提高已有系统的文档管理和系统维护的有效性。简而言之,设计模式可以帮助设计者更快更好地完成系统设计。

一共23种设计模式!

按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。

创建型模式用来处理对象的创建过程;结构型模式用来处理类或者对象的组合;行为型模式用来对类或对象怎样交互和怎样分配职责进行描述。

创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:

工厂方法模式(FactoryMethodPattern)

抽象工厂模式(AbstractFactoryPattern)

建造者模式(BuilderPattern搜索)

原型模式(PrototypePattern)

单例模式(SingletonPattern)

结构型模式用来处理类或者对象的组合,主要包含以下7种设计模式:

适配器模式(AdapterPattern)

桥接模式(BridgePattern)

组合模式(CompositePattern)

装饰者模式(DecoratorPattern)

外观模式(FacadePattern)

享元模式(FlyweightPattern)

代理模式(ProxyPattern)

行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:

责任链模式(ChainofResponsibilityPattern)

命令模式(CommandPattern)

解释器模式(InterpreterPattern)

迭代器模式(IteratorPattern)

中介者模式(MediatorPattern)

备忘录模式(MementoPattern)

观察者模式(ObserverPattern)

状态模式(StatePattern)

策略模式(StrategyPattern)

模板方法模式(TemplateMethodPattern)

访问者模式(VisitorPattern)

一、工厂方法模式(FactoryMethodPattern)

一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使一个类的实例延迟到其子类。

1、1适用于以下情况


1、当一个类不知道它所必须创建的对象的类的时候。


2、当一个类希望由它的子类来指定它所创建的对象的时候。


3、当将创建对象的职责委托给多个实现类中的某一个,并且希望将哪一个实现子类是代理者这一信息局部化的时候。

4、工厂类负责创建的对象比较少;

5、客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;

6、由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。


1、2类图

1、3实例:工厂方法模式之多数据库链接的实现

用工厂方法模式开发多数据库连接类,是工厂方法模式最好的应用方式,也是很多初级使用设计模式的程序员都会涉及到的,下面是具体代码:

//数据库连接接口

packageutil;

importjava.sql.*;

publicinterfaceDBConnection{

//获取连接对象

publicConnectiongetcon();

//关闭数据库的链接

publicvoidclosed(ResultSetset,PreparedStatementpre,Connectioncon);

}

//mysql连接实现类

packageutil;

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.PreparedStatement;

importjava.sql.ResultSet;

importjava.sql.SQLException;

publicclassDBConnectionMysqlIMimplementsDBConnection{

privatefinalStringDRIVER="com.mysql.jdbc.Driver";

privatefinalStringURL="jdbc:mysql://localhost:3306/angel";

publicConnectiongetcon(){

Connectioncon=null;

try{

Class.forName(DRIVER);

con=DriverManager.getConnection(URL,"root","root");

}catch(ClassNotFoundExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

returncon;

}

publicvoidclosed(ResultSetset,PreparedStatementpre,Connectioncon){

try{

if(set!=null){

set.close();

}

if(pre!=null){

pre.close();

}

if(con!=null){

con.close();

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}

}

//sqlserver连接实现类

packageutil;

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.PreparedStatement;

importjava.sql.ResultSet;

importjava.sql.SQLException;

publicclassDBConnectionSqlIMimplementsDBConnection{

privatefinalStringDRIVER="com.microsoft.sqlserver.jdbc.SQLServerDriver";

privatefinalStringURL="jdbc:sqlserver://localhost:1433;DatabaseName=angel";

publicConnectiongetcon(){

Connectioncon=null;

try{

Class.forName(DRIVER);

con=DriverManager.getConnection(URL,"sa","sa");

}catch(ClassNotFoundExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

returncon;

}

publicvoidclosed(ResultSetset,PreparedStatementpre,Connectioncon){

try{

if(set!=null){

set.close();

}

if(pre!=null){

pre.close();

}

if(con!=null){

con.close();

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}

}

//工厂类

packageutil;

publicclassDBConFactory{

publicstaticDBConnectiongetcon(Stringname){

DBConnectionconif=null;

try{

Classc=Class.forName(name);

conif=(DBConnection)c.newInstance();

}catch(ClassNotFoundExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}catch(InstantiationExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}catch(IllegalAccessExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

returnconif;

}

}

//测试类

packagemodel;

importjava.util.ArrayList;

importjava.util.List;

importutil.DBConFactory;

importutil.DBConnection;

importjava.sql.*;

publicclassUsersDaoIMimplementsUsersDao{

privatefinalStringSQL_ADD="insertintousers(name,pass)values(?,?)";

privatefinalStringSQL_UPDATE="updateuserssetname=?,pass=?whereid=?";

privatefinalStringSQL_DELETE="deletefromuserswhereid=?";

privatefinalStringSQL_SELECT="select*fromusers";

privatefinalStringSQL_LOGIN="select*fromuserswherename=?andpass=?";

privatefinalStringSQL_GETINFO="select*fromuserswhereid=?";

privatefinalStringSQL_TEXT="selectcount(*)fromuserswherename=?";

DBConnectionconif=DBConFactory.getcon("util.DBConnectionSqlIM");

publicbooleanadd(UsersInfou){

booleanb=false;

Connectioncon=null;

PreparedStatementpre=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_ADD);

pre.setString(1,u.getName());

pre.setString(2,u.getPass());

inti=pre.executeUpdate();

if(i>0){

b=true;

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(null,pre,con);

}

returnb;

}

publicbooleandelete(inti){

booleanb=false;

Connectioncon=null;

PreparedStatementpre=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_DELETE);

pre.setInt(1,i);

intk=pre.executeUpdate();

if(k>0){

b=true;

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(null,pre,con);

}

returnb;

}

publicbooleanlogin(UsersInfou){

booleanb=false;

ResultSetset=null;

Connectioncon=null;

PreparedStatementpre=null;

UsersInfouser=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_LOGIN);

pre.setString(1,u.getName());

pre.setString(2,u.getPass());

set=pre.executeQuery();

while(set.next()){

user=newUsersInfo();

user.setId(set.getInt(1));

user.setName(set.getString(2));

user.setPass(set.getString(3));

}

if(user!=null){

b=true;

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(set,pre,con);

}

returnb;

}

publicListselect(){

Listlist=newArrayList();

ResultSetset=null;

Connectioncon=null;

PreparedStatementpre=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_SELECT);

set=pre.executeQuery();

while(set.next()){

UsersInfou=newUsersInfo();

u.setId(set.getInt(1));

u.setName(set.getString(2));

u.setPass(set.getString(3));

list.add(u);

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(set,pre,con);

}

returnlist;

}

publicbooleanupdate(UsersInfou){

booleanb=false;

Connectioncon=null;

PreparedStatementpre=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_UPDATE);

pre.setString(1,u.getName());

pre.setString(2,u.getPass());

pre.setInt(3,u.getId());

inti=pre.executeUpdate();

if(i>0){

b=true;

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(null,pre,con);

}

returnb;

}

publicUsersInfogetInfoById(inti){

ResultSetset=null;

Connectioncon=null;

PreparedStatementpre=null;

UsersInfouser=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_GETINFO);

pre.setInt(1,i);

set=pre.executeQuery();

while(set.next()){

user=newUsersInfo();

user.setId(set.getInt(1));

user.setName(set.getString(2));

user.setPass(set.getString(3));

}

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}finally{

conif.closed(set,pre,con);

}

returnuser;

}

publicbooleantext(Stringname){

booleanb=false;

Connectioncon=null;

PreparedStatementpre=null;

ResultSetset=null;

try{

con=conif.getcon();

pre=con.prepareStatement(SQL_TEXT);

pre.setString(1,name);

set=pre.executeQuery();

intcont=0;

while(set.next()){

cont=set.getInt(1);

break;

}

if(cont>0){

b=true;

}

}catch(SQLExceptione){

e.printStackTrace();

}finally{

conif.closed(set,pre,con);

}

returnb;

}

}

1、4优缺点

  优点:

  工厂类是整个模式的关键。包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。

  缺点:

  由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

  当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;

这些缺点在工厂方法模式中得到了一定的克服。

二、单例模式(SingletonPattern)

保证一个类仅有一个实例,提供一个访问它的全局访问点。

2、1适用于以下情况

1、当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。


2、当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

2、2类图

2、3实例

典型的单例模式

publicclassSingleton{

privatestaticSingletonsing;

privateSingleton(){

}

publicst*ticSingletonget*nstance(){

if(sing==null){

sing=newSingleto*();

}

returnsing;

}

}

Test

publicclassTest{

publicstaticvoid*ain(*tring[]args){

Singletonsing=Singleton.getInstance();

Singletonsi*g2=Singleton.getI*stance();

System.out.println(sing);

System.out.pr*ntln(sing2);

}

}

result

singleton.Singleton@1c78e57

singleton.Singleton@1c78e57

2、3、1饿汉式单例类

//饿汉式单例类.在类初始化时,已经自行实例化

publicclassSingleton1{

//私有的默认构造子

privateSingleton1(){}

//已经自行实例化

privatestaticfinalSingleton1single=newSingleton1();

//静态工厂方法

publicstaticSingleton1getInstance(){

returnsingle;

}

}

2、3、2懒汉式单例类

//懒汉式单例类.在第一次调用的时候实例化

publicclassSingleton2{

//私有的默认构造子

privateSingleton2(){}

//注意,这里没有final

privatestaticSingleton2single=null;

//静态工厂方法

publicsynchronizedstaticSingleton2getInstance(){

if(single==null){

single=newSingleton2();

}

returnsingle;

}

}

2、3、3登记式单例类

importjava.util.HashMap;

importjava.util.Map;

//登记式单例类.

//类似Spring里面的方法,将类名注册,下次从里面直接获取。

publicclassSingleton3{

privatestaticMap<String,Singleton3>map=newHashMap<String,Singleton3>();

static{

Singleton3single=newSingleton3();

map.put(single.getClass().getName(),single);

}

//保护的默认构造子

protectedSingleton3(){}

//静态工厂方法,返还此类惟一的实例

publicstaticSingleton3getInstance(Stringname){

if(name==null){

name=Singleton3.class.getName();

System.out.println("name==null"+"--->name="+name);

}

if(map.get(name)==null){

try{

map.put(name,(Singleton3)Class.forName(name).newInstance());

}catch(InstantiationExceptione){

e.printStackTrace();

}catch(IllegalAccessExceptione){

e.printStackTrace();

}catch(ClassNotFoundExceptione){

e.printStackTrace();

}

}

returnmap.get(name);

}

//一个示意性的商业方法

publicStringabout(){

return"Hello,IamRegSingleton.";

}

publicstaticvoidmain(String[]args){

Singleton3single3=Singleton3.getInstance(null);

System.out.println(single3.about());

}

}

静态方法getInstance()返回这个类的一个实例。注重即使这个实例需要是子类,也无须修改API。

一般来说,不需要提供一个getInstance()方法,因为INSTANCE变量可以声明为public的。但是,getInstance()方法可以提供更好的灵活性,尤其是以后系统的设计发生变化的时候。出色的虚拟机实现可以将getInstance()方法进行内联。

编写一个好的单例模式的类并非这么简单,假如需要使得自己的单例类是可序列化的,那么必须提供一个readResolve()方法:

/**

*EnsureSingletonclass

*/

privateObjectreadResolve()throwsObjectStreamException{

returnINSTANCE;

}

提供readResolve()方法后,反序列化的时候将只有一个对象产生,无论调用了多少次getInstance()方法。假如不提供readResolve()方法,当反序列化的时候,每次都会创建一个新的对象实例。

三、值对象模式(Valueobject)

值对象(valueobject)模式通过减少分布式通信的消息而促进数据的交换,通常这里所指的通信是在Web层和服务层之间。在一个远程调用中,一个单一值对象可以被用来取出一系列相关数据并提供给客户。

3、1适用于以下情况

简化传值

主要用于减少数据传送次数,常用在SSH中。一般采用数据传输对象工厂来满足这种模式的设计需求,它可以帮助将客户端与域模型分离。视图对象是一个普通的Java类,它封装了要传送的批量的数据。当客户端需要读取服务器端的数据的时候,服务器端将数据封装在视图对象中中,这样客户端就可以在一个网络调用中获得它需要的所有数据。使用视图对象的时候,一个主要问题是建立什么样的视图对象:这个对象能够容纳哪些数据,对象的结构是什么,这个对象的数据是如何封装的。

视图对象是服务器端和客户端进行通信的一个协议格式,合理的DTO设计将会使得服务器和客户端的通信更加顺畅。

分布式应用(跨域)

在分布式系统中,PO完全位于服务器端。根据持久化对象可否直接传递到客户端,域对象可以分为两种类型:一种是服务器端的持久化对象不可以直接传递到客户端,比如EJB中的实体Bean是不能被传递到客户端的;一种是持久化对象可以直接传递到客户端,比如Hibernate中的PO变为detachedobject以后就可以传递到客户端。

3、2类图

3、3实例

我们列举一个例子,假设某名为project的业务对象被模拟或者实现为一个实体bean。当客户端调用值对象的getProjectData()方法时,该project实体bean需要通过该值对象向客户端发送数据。如下例:

publicclassProjectVOimplementsjava.io.Serializable{

privateStringprojectId;

privateStringprojectName;

privateStringmanagerId;

privateStringcustomerId;

privateDatestartDate;

privateDateendDate;

privatebooleanstarted;

privatebooleancompleted;

privatebooleanaccepted;

privateDateacceptedDate;

privateStringprojectDescription;

privateStringprojectStatus;

//Valueobjectconstructors...

//以下就是具体的每一个的get和set方法

}

3、4优势

域模型结构可以在一次网络调用中复制到客户端,客户端可以读取、更新这个对象而不需要额外的网络调用开销,而且客户端还可以通过将更新后的视图对象回传到服务器端以更新数据易于实现快速开发。通过使用域视图对象可以直接将域模型在层间传输,减少了工作量,可以快速地构建出一个应用。

可定制的视图对象,使它仅封装客户端需要的数据的任意组合,完全与服务器端的域模型相分离。定制对象与域对象的区别就是它不映射到任何服务器端的域模型。

定制视图对象主要用于只读操作,也就是视图对象只能用来显示,而不能接受改变。既然定制视图对象仅仅是一个数据的集合,和任何服务端对象没有必然的关系,那么对定制视图对象进行更新就是没有意义的了。

四、DAO模式(DataAccessObject)

DAO是DataAccessObject数据访问接口,数据访问:故名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。数据访问对象(dataaccessobject,DAO)模式将数据访问逻辑抽象为特殊的资源,也就是说将系统资源的接口从其底层访问机制中隔离出来;通过将数据访问的调用打包,数据访问对象可以促进对于不同数据库类型和模式的数据访问。

4、1DAO的功能

1、DAO用来封装DataSource的..就比如,Connectionconn=DAOFacotry.createConnection()

就可以把Driver.URL.username,passpword这一些放在DAO中以后要更改数据库的类型.比如要把MSSQL换成Oracle的话,只需要更改DAOFacory里面的getConnection()里面的Driver.URL.之类的。

  2、DAO也是把对数据库的操作(比如最基本的CRUD操作)全部封装在里面。

  比如说你要你要插入一个新的用户..那么.在DAO中我们只需要提供一个insertUser(Useruser)这一个方法就可以了,具体的操作是在DAO实现类中实现的。

  那么对于要调用DAO的时候.我们只要知道insertUser(User)是用来插入一个新的用户,而不需要知道是如何实现的。

一般DAO是与AbstractFactory模式一起来用的。

4、2类图

对于序列图中的组件加以解释如下:

(1)业务对象(BusinessObject)

表示数据的用户,它需要对于数据的访问,一个业务对象可以用会话bean、实体bean或

是其他Java程序来实现。

(2)数据访问对象(DataAccessObject)

数据访问对象是这种模式中的主题,它提供了底层数据访问的对象,并将其提供给业务对象以使得后者能够透明地访问数据源;同时业务对象也将数据的加载和存储操作移交给数据访问对象处理。

(3)数据源(Datasource)

这里指的是数据源的物理实现,这个数据源可以是一个数据库,包括关系型数据库、面向

对象数据库或文件系统。

(4)值对象(TransferObject)

这里的值对象指的是数据载体。数据访问对象可以使用值对象来向用户返回数据,而数据

访问对象同样可以从用户那里得到值对象来对数据源中的数据进行更新。

4、3实例

Factory来建立数据库和定位具体的DAO(比如说是UserDao、CustomerDao),一般将getConnection设置为static,也可以把HibernateSessionFactory这一个公共类放在这一AbstractFactory类中去。

 

publicclassDAOFactory{

  privatestaticfinalSessionFactorysessionFacotory;

  //定义一个TrheadLocal.

  staticSessioncurrentSession().....

  publicUserDaogetUserDAO(){returnnewUserDaoImpl(sesssion);}

  pulbicOtherDaogetOtherDAO(){returnnewOtherDaoImpl(session);}

  ......

  }

  publicinterfaceUserDao{

  publicinsertUser(FormBean)

  publicupdateUser(FormBean);

  }

  然后就实现DAO的接口:(Struts的FormBean...VO来的..)

  publicclassUserDaoImplimplementsUserDao{

  privateSessionsession;

  publicUserDaoImpl(Sessionsession){

  this.session=session;

  }...

  publicinsertUser(FormBean){

  ..//..

  session.save(UserPO);

  ..//..

  returnFormBean;

  }

  publicFormBeanupdateUser(FormBean){

  ..//..

  session.update(UserPO);

  ..//..

  returnFormBean;

  }

  }

  最后定义你的PO:

  publicclassUserPO{

  Stringfirstname,lastname,password..........

}

4、4优劣势

这种设计模式的优势:

透明性好

业务对象可以在不知道数据源实现细节的情况下访问数据。由于一切数据访问细节被数据访问对象所隐藏,所以这种访问过程是透明的。

可移植性好

在应用系统中添加数据访问对象,可以使得前者能够很方便地移植到另外一种数据库实现上。业务对象与数据实现是隔离的,所以在移植过程中,仅仅对数据访问对象进行一些变化即可。

减少业务对象的代码复杂度

由于数据访问对象可以管理所有的数据访问复杂细节,这也就简化了业务模块和其他数据客户的代码。同时也提高了应用系统的整体可读性和开发率。

集中处理所有数据访问

由于所有的数据访问操作都移交给数据访问对象,这样应用系统其他部分就与数据访问实现隔离开来,而全部相关操作都与数据访问对象集中处理,这样也使得相关操作更加容易被维护和管理。

这种设计模式的缺陷:

添加了额外的层面

数据访问对象在数据用户和数据源之间添加了一个层面,也就增加了一些额外的设计和实现的负担。当然,我们认为它是物有所值的。

总之,在开发人员选择不同模式的时候,应该注意,一定的模式对应于一定的应用层次。



五、门面模式(Facade)

将有顺序的,有规律的,事情交给一个门面来做。要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,门面模式提供一个高层次的接口,使得子系统更容易使用。

5、1适用情况

1、为一个复杂子系统提供一个简单接口。

2、提高子系统的独立性。

3、在层次化结构中,可以使用Facade模式定义系统中每一层的入口。

4、希望封装和隐藏原系统时。

5、2类图

非门面模式(保安系统)

门面模式(保安系统)

5、3实例

餐馆吃饭的问题。

在有些餐馆,客人进去吃饭是需要自己找座位,自己倒茶,自己写菜单,然后将菜单交给服务员,由服务员去完成剩下的工作。

但是也有很多那种高级的餐厅,或者服务很周到的餐厅是这样做的,你一进门,就会有服务员领着你到给你安排座位(我们现在假设安排座位是专门一个部门来完成的,只是这个服务员直接问了座位部那些座位是空的,然后领着去对应的地方就可以了)。然后你坐下之后服务员给你端茶倒水(茶水有茶水部门来负责泡茶,烧水之类的),然后你告诉服务员我现在要吃什么菜,服务员帮你写下菜单就可以了。

如果是这样的话,你每次吃饭是不是会心里很爽呢?对啊,你什么也没有做,都是服务员帮你完成的,你完全没有自己去找座位,自己去倒茶,自己写菜单。

packagecom.gengu.门面模式;

/**

*门面模式的

*这是餐厅的一个侍者

*他负责帮客人端茶递水,找座位,写菜单之类的操作

**/

publicclassWaiter{

BoardDepartmentboardDepartment=newBoardDepartment();

TeaDepartmentteaDepartment=newTeaDepartment();

MenuDepartmentmenuDepartment=newMenuDepartment();

//帮助客人

publicvoidhelpCustomer(Stringmessage){

boardDepartment.providBoard();

teaDepartment.Provide();

menuDepartment.providMenu(message);

}

}

packagecom.gengu.门面模式;

/**

*座位系统

*帮助用户找座位

**/

publicclassBoardDepartment{

//给客人找空位

publicvoidprovidBoard(){

System.out.println("给客人分配座位号为"+newjava.util.Random().nextInt(100));

}

}

packagecom.gengu.门面模式;

/**

*茶水部

*专门负责给人提供茶水

**/

publicclassTeaDepartment{

//提供茶水

publicvoidProvide(){

System.out.println("给客人提供乌龙茶");

}

}

packagecom.gengu.门面模式;

/**

*帮客人完成菜单

*菜单部门

**/

publicclassMenuDepartment{

//给客人点菜

publicvoidprovidMenu(Stringmessage){

System.out.println("客人点的菜是"+message);

//doSomeThing

}

}

packagecom.gengu.门面模式;

publicclassClient{

publicstaticvoidmain(String[]args){

Waiterwaiter=newWaiter();

waiter.helpCustomer("鱼香肉丝");

}

}

六、装饰模式(Decorator)

给一个类添加一些额外的职责,并且在添加这些额外的职责时不会控制该类的执行逻辑。

6、1装饰模式的特点

(1)装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。

(2)装饰对象包含一个真实对象的索引

(3)装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。

(4)装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继续来实现对给定类的功能扩展。

6、2类图

抽象构件:原始的功能接口

具体构件:具体的原始功能类

装饰角色:持有具体构件类的对象,以便执行原有功能

具体装饰:具体扩展的功能在这里

6、3实例

晚上+开车实例。

packagecom.drector;

抽象构件:

/**

*抽象接口,规范准备接收附加责任的对象

*/

publicinterfaceComponent{

publicvoidoperation();

}

具体构件:

packagecom.drector;

/**

*接收附加责任,此类型的类可以有多个,只对应一个Decorator类

*/

publicclassConcreteComponentimplementsComponent{

publicConcreteComponent(){}

publicvoidoperation()

{

System.out.println("开车");

}

}

具体构件:

packagecom.drector;

/**

*装饰角色,持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口

*/

publicclassDecoratorimplementsComponent{

privateComponentcomponent;

publicDecorator(){}

publicDecorator(Componentcomponent)

{

this.component=component;

}

publicvoidoperation(){

component.operation();

}

}

装饰角色:

packagecom.drector;

/**

*添加附加责任

*/

publicclassConcreteDecoratorextendsDecorator{

publicConcreteDecorator(){}

publicConcreteDecorator(Componentcomponent)

{

super(component);

}

publicvoidoperation()

{

this.addedOperation();

super.operation();

}

publicvoidaddedOperation()

{

System.out.println("晚上");

}

}

测试:

packagecom.drector;

/**

*客户端类

*/

publicclassClient{

publicstaticvoidmain(String[]args){

Componentcomponent=newConcreteComponent();

Decoratordecorator=newConcreteDecorator(component);

//客户端不变,但已增加了责任

decorator.operation();

}

}

输出结果:

晚上

开车

七、适配器模式(Adapter)

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

7、1适用以下情况

1、你想使用一个已经存在的类,而它的接口不符合你的需求。

2、你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。

3、(仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

7、2类图

其中:

•Target

—定义Client使用的与特定领域相关的接口。

•Client

—与符合Target接口的对象协同。

•Adaptee

—定义一个已经存在的接口,这个接口需要适配。

•Adapter

—对Adaptee的接口与Target接口进行适配

7、3实例

在生活中最简单的例子就是电源适配器,如手机适配器,我们的家用电源是220V的,但是,对于手机来说,根本大不了这么多,所以,在这种情况下,需要电源适配器来为我们提供适合手机的电压。

packagecom.visionsky.DesignPattern;

publicclassAdaterDemoInLife{

/**

*@paramargs

*/

publicstaticvoidmain(String[]args){

//TODOAuto-generatedmethodstub

MobilePowerAdaptermpa=newMobilePowerAdapter();

mpa.GetPower10V();

}

}

interfaceITarget{

intGetPower10V();

}

classPower{

intGetPower220V(){

return220;

}

}

classMobilePowerAdapterimplementsITarget

{

privatePowerpower;

publicMobilePowerAdapter(){

this.power=newPower();

}

@Override

publicintGetPower10V(){

//TODOAuto-generatedmethodstub

power.GetPower220V();

//将220v转变成10v,具体做法就不写了,大家明白就行

return10;

}

}

八、责任链模式(ChainofResponsibility)

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

8、1类图

8、2实例

申请聚餐费用的管理。  

很多公司都是这样的福利,就是项目组或者是部门可以向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动。

  申请聚餐费用的大致流程一般是:由申请人先填写申请单,然后交给领导审批,如果申请批准下来,领导会通知申请人审批通过,然后申请人去财务领取费用,如果没有批准下来,领导会通知申请人审批未通过,此事也就此作罢。

  不同级别的领导,对于审批的额度是不一样的,比如,项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。

  也就是说,当某人提出聚餐费用申请的请求后,该请求会经由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求。

  可以使用责任链模式来实现上述功能:当某人提出聚餐费用申请的请求后,该请求会在项目经理—〉部门经理—〉总经理这样一条领导处理链上进行传递,发出请求的人并不知道谁会来处理他的请求,每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级别的领导,只要有领导处理了,传递就结束了。

  需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态地组合职责链,实现不同的功能要求了。  

publicclassClient{

publicstaticvoidmain(String[]args){

//先要组装责任链

Handlerh1=newGeneralManager();

Handlerh2=newDeptManager();

Handlerh3=newProjectManager();

h3.setSuccessor(h2);

h2.setSuccessor(h1);

//开始测试

Stringtest1=h3.handleFeeRequest("张三",300);

System.out.println("test1="+test1);

Stringtest2=h3.handleFeeRequest("李四",300);

System.out.println("test2="+test2);

System.out.println("---------------------------------------");

Stringtest3=h3.handleFeeRequest("张三",700);

System.out.println("test3="+test3);

Stringtest4=h3.handleFeeRequest("李四",700);

System.out.println("test4="+test4);

System.out.println("---------------------------------------");

Stringtest5=h3.handleFeeRequest("张三",1500);

System.out.println("test5="+test5);

Stringtest6=h3.handleFeeRequest("李四",1500);

System.out.println("test6="+test6);

}

}

publicabstractclassHandler{

/**

*持有下一个处理请求的对象

*/

protectedHandlersuccessor=null;

/**

*取值方法

*/

publicHandlergetSuccessor(){

returnsuccessor;

}

/**

*设置下一个处理请求的对象

*/

publicvoidsetSuccessor(Handlersuccessor){

this.successor=successor;

}

/**

*处理聚餐费用的申请

*@paramuser申请人

*@paramfee申请的钱数

*@return成功或失败的具体通知

*/

publicabstractStringhandleFeeRequest(Stringuser,doublefee);

}

publicclassProjectManagerextendsHandler{

@Override

publicStringhandleFeeRequest(Stringuser,doublefee){

Stringstr="";

//项目经理权限比较小,只能在500以内

if(fee<500)

{

//为了测试,简单点,只同意张三的请求

if("张三".equals(user))

{

str="成功:项目经理同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}else

{

//其他人一律不同意

str="失败:项目经理不同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}

}else

{

//超过500,继续传递给级别更高的人处理

if(getSuccessor()!=null)

{

returngetSuccessor().handleFeeRequest(user,fee);

}

}

returnstr;

}

}

publicclassDeptManagerextendsHandler{

@Override

publicStringhandleFeeRequest(Stringuser,doublefee){

Stringstr="";

//部门经理的权限只能在1000以内

if(fee<1000)

{

//为了测试,简单点,只同意张三的请求

if("张三".equals(user))

{

str="成功:部门经理同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}else

{

//其他人一律不同意

str="失败:部门经理不同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}

}else

{

//超过1000,继续传递给级别更高的人处理

if(getSuccessor()!=null)

{

returngetSuccessor().handleFeeRequest(user,fee);

}

}

returnstr;

}

}

publicclassGeneralManagerextendsHandler{

@Override

publicStringhandleFeeRequest(Stringuser,doublefee){

Stringstr="";

//总经理的权限很大,只要请求到了这里,他都可以处理

if(fee>=1000)

{

//为了测试,简单点,只同意张三的请求

if("张三".equals(user))

{

str="成功:总经理同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}else

{

//其他人一律不同意

str="失败:总经理不同意【"+user+"】的聚餐费用,金额为"+fee+"元";

}

}else

{

//如果还有后继的处理对象,继续传递

if(getSuccessor()!=null)

{

returngetSuccessor().handleFeeRequest(user,fee);

}

}

returnstr;

}

}

8、3总结

一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。

  在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。

  纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。

九、建造者模式(BuilderPattern)

建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。举个简单的例子,如汽车,有很多部件,车轮,方向盘,发动机还有各种小零件等等,部件很多,但远不止这些,如何将这些部件装配成一部汽车,这个装配过程也很复杂(需要很好的组装技术),builder模式就是为了将部件和组装分开。

与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。

9、1适用情况

1、需要生成的产品有复杂的内部结构

2、需要生成的产品对象的属性互相依赖

3、在对象的创建过程中会使用到其他对象

9、2类图

1、抽象建造者角色

2、具体建造者角色

3、导演者角色

4、产品角色

9、3实例

publicinterfaceBuilder{

    voidbuildPartA();

    voidbuildPartB();

    voidbuildPartC();

  

    ProductgetResult();

}

//具体建造工具

  publicclassConcreteBuilderimplementsBuilder{

    PartpartA,partB,partC;

    publicvoidbuildPartA(){

      //这里是具体如何构建partA的代码

    };

    publicvoidbuildPartB(){

      //这里是具体如何构建partB的代码

    };

    publicvoidbuildPartC(){

      //这里是具体如何构建partB的代码

    };

    publicProductgetResult(){

      //返回最后组装成品结果

    };

  }

//建造者

  publicclassDirector{

    privateBuilderbuilder;

  

    publicDirector(Builderbuilder){

      this.builder=builder;

    }

    publicvoidconstruct(){

      builder.buildPartA();

      builder.buildPartB();

      builder.buildPartC();

    }

  }

  publicinterfaceProduct{}

publicinterfacePart{}

下面是调用builder的方法:

  ConcreteBuilderbuilder=newConcreteBuilder();

  Directordirector=newDirector(builder);

  

  director.construct();

  Productproduct=builder.getResult();

转:九中常用的设计模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: