常见设计模式精学

来源:互联网 发布:剑灵捏脸数据 灵女 萌 编辑:程序博客网 时间:2024/05/27 06:56

设计模式常常被分为如下三类:

创建型:创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构。创建型模式主要有简单工厂模式、工厂方法、抽象工厂模式、单例模式、生成器模式和原型模式。

结构型:用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式、桥接模式、组合器模式、装饰器模式、门面模式、享元模式和代理模式。

行为型:用于帮助系统间各个对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式、解释器模式、迭代器模式、终结者模式、备忘录模式、观察者模式、状态模式、策略模式、模板模式和访问者模式。

1.单例模式

如果一个类始终只能创建一个实例,则这个类被称为单例类,这种模式就被称为单例模式。

对于Spring框架而言,可以在配置Bean实例时指定scope=“singleton”来配置单例模式。不仅如此,如果配置<bean../>元素时没有指定scope属性,则该Bean实例默认是单例的行为方式。Spring推荐将所有业务逻辑组件、DAO组件、数据源组件等配置成单例的行为方式,因为这些组件无需保存任何用户状态。

2.工厂模式

将多个类对象交给工厂类来生成的设计方式被称为工厂模式。它的优势是让对象的调用者和对象创建过程分离,当对象调用者需要对象时,直接向工厂请求即可。从而避免了对象的调用者与对象的实现类以硬编码方式耦合,以提高系统的可维护性、可扩展性。工厂模式也有一个小小的缺陷:当产品修改时,工厂类也要做相应的修改。

3.代理模式

代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用每个对象时,客户端实际上也不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理。

在这种设计方式下,系统会为某个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个Java对象代表另一个Java对象来采取行动。在某些情况下,客户端代码不想或不能够直接调用被调用者,代理对象可以在客户和目标对象之间起到中介的作用。

Hibernate延迟加载所采用的设计模式就是代理模式。当A实体和B实体之间存在关联关系时,Hibernate默认启用延迟加载,当系统加载A实体时,A实体关联的B实体并未被加载出来,A实体所关联的B实体全部是代理对象—只有等到A实体真正需要访问B实体时,系统才会去数据库里抓取B实体所对应的记录。

Hibernate的延迟加载充分体现了代理模式的优势:当系统加载A实体时,也许只需要访问A实体对应的记录,根本不会访问A的关联对象。如果不采用代理模式,系统需要在加载A 实体时,同时加载A实体烦人所有关联实体,这对系统造成很大的压力。

除了出于性能考虑使用代理模式之外,代理模式还有另外一种常用场景:当目标对象的功能不足以满足客户端需求时,系统可以为该对象创建一个代理对象,而代理对象可以增强原目标对象的功能。

4.命令模式

某个方法需要完成某一个功能,完成这个功能的大部分步骤已经确定,但可能有少量具体步骤的处理行为无法确定,所以我们必须把处理行为作为参数传入该方法。

因为Java不允许代码块单独存在,因此我们必须把该代码封装成一个方法。在Java语言中,类才是一等公民,方法也不能独立存在,所以我们实际传入该方法的应该是一个对象,该对象通常是某个接口的匿名实现类的实例,该接口通常被称为命令接口,这种设计方式也被称为命令模式。

例如Spring框架中HibernateTemplate的executeXxx()方法,需要接受一个HibernateCallback接口:

//定义一个HibernateCallback接口,该接口封装持久化处理行为public interface HibernateCallback{    Object doInHibernate(Session session);}

上面的HibernateCallback接口就是一个典型的Command接口,一个HibernateCallback对象封装了自定义的持久化处理。使用Hibernate进行分页查询:

List list = getHibernateTemplate().executeFind(new HibernateCallback(){    //实现HibernateCallback接口必须实现的方法    public Object doInHibernate(Session session) throws HibernateException,SQLException{        //执行Hibernate分页查询        List list = session.createQuery(hql)        .setFirstResult(offset)        .setMaxResults(pageSize)        .list();        return result;    }});return list;

5.策略模式

策略模式用于封装系列的算法,这些算法通常被封装在一个被称为Context的类中,客户端程序可以自由选择其中的一种算法,或让Context为客户端选择一个最佳的算法—使用策略模式的优势是为了支持算法的自由切换。策略模式原理应用Java的多态性,并且定义父类指向子类的引用。

Hibernate的Dialect类就应用了这种模式,Dialect代表各数据库方言的抽象父类,它的不同子类就代表了一种特定的数据库访问策略。为了让客户端代码与具体的数据库、具体的Diatect实现类分离,Hibernate需要在hibernate.cfg.xml文件中指定应用所使用的Dialect子类。

Spring的Resource接口也是一个典型的策略接口,不同的实现类代表了不同的资源访问策略。当然Spring可以非常智能的选择合适的Resource实现类,通常来说,Spring可以根据前缀来决定使用合适的Resource实现类,还可根据ApplicationContext的实现类来决定使用合适的Resource实现类。

6.门面模式

随着系统的不断改进和开发,它们会变得越来越复杂,系统会生成大量的类,这使得程序流程更难被理解。门面模式可为这些类提供一个简化的接口,从而简化访问这些类的复杂性,有时这种简化可能降低访问这些底层类的灵活性,但除了要求特别苛刻的客户端之外,它通常都可以提供所需的全部功能。

门面模式也被称为正面模式、外观模式,这种模式用于将一组复杂的类包装到一个简单的外部接口中。通俗来说,就是将实现某类业务功能所需的一系列相应逻辑代码封装成为一个具体的类进行调用。

当我们的程序使用Spring的HibernateTemplate类的find()方法时,程序只要此一行代码即可得到查询返回的List,但实际上find()方法后隐藏了如下代码:

Session session = new Session();Query query = session.createQuery(hql);for(int i = 0;i<args.length;i++){    query.setParameter(i,args[i]);}query.list();

因此我们可以认为HibernateTemplate是SessionFactory、Session、Query等类的门面,当客户端程进行序需要进行持久化查询时,程序无需调用这些类,而是直接调用HibernateTemplate门面类的方法即可。

除此之外,Java EE 应用里使用业务逻辑组件封装DAO组件也是典型的门面模式—每个业务逻辑组件都是众多DAO组件的门面,系统的控制器类无须访问DAO组件,而是由业务逻辑方法来组合多个DAO方法以完成所需功能,而action只需与业务逻辑组件交互即可。

7.桥接模式

桥接模式是一种结构型模式,它主要应对的是:由于实际的需要,某个类具有两个或两个以上的维度变化,如果只是使用继承将无法实现这种需要,或者使得设计变得相当臃肿。

桥接模式在Java EE架构中有非常广泛的用途,由于Java EE应用需要实现跨数据库的功能,程序为了在不同数据库之间迁移,因此系统需要在持久化技术这个维度上存在改变;除此之外,系统也需要在不同业务逻辑实现之间迁移,因此也需要在逻辑实现这个维度上存在改变,这正好符合桥接模式的使用场景。因此,Java EE应用都会推荐使用业务逻辑组件和DAO组件分离的结构,让Dao组件负责持久化技术这个维度上的改变,让业务逻辑组件负责逻辑实现这个维度上的改变。由此可见,Java EE应用中常见的DAO模式正是桥接模式的应用。

8.观察者模式

观察者模式定义了对象间的一对多依赖关系,让一个或多个观察者对象观察一个主体对象。当主体对象的状态发生变化时,系统能通知所有的依赖于此对象的观察者对象,从而使得观察者对象能够自动更新。在观察者模式中,被观察者的对象常常也被称为目标或主题,依赖的对象被称为观察者。

Java时间机制的底层实现,本身就是通过观察者模式实现的。

0 0
原创粉丝点击