复习设计模式

Posted on 2013-12-31 00:21  香蕉菊花小哥  阅读(264)  评论(0编辑  收藏  举报

摘自:

http://zz563143188.iteye.com/blog/1847029

http://www.cnblogs.com/hxsyl/archive/2013/03/19/2969489.html

十分感谢原作者!

 

总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。

 

 设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。

 

 


1. 工厂方法(Factory Method)模式分为三种:
1.1 普通工厂模式: 使用变量生产产品
1.2 多个工厂方法模式: 工厂提供多个PUBLIC方法生产不同产品
1.3 静态工厂方法模式: 静态工厂,不需工厂实例,其他同1.2

工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误, 不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。


2. 抽象工厂模式(Abstract Factory)
多个产品有同一接口,多个工厂也有同一接口,使用接口实例化工厂。
拓展性好!


3. 单例模式(Singleton)
单例对象能保证在一个JVM中,该对象只有一个实例存在。
3.1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
3.2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3.3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

单例模式分三种:懒汉式单例(在第一次调用的时候实例化)、饿汉式单例(在类初始化时,已经自行实例化 )、登记式单例(类似Spring里面的方法,将类名注册,下次从里面直接获取)三种。请看http://www.cnblogs.com/hxsyl/archive/2013/03/19/2969489.html

单例模式有一下特点:
3.4、单例类只能有一个实例。
3.5、单例类必须自己自己创建自己的唯一实例。
3.6、单例类必须给所有其他对象提供这一实例。

要保证线程安全:

public class Singleton {  
      
        /* 私有构造方法,防止被实例化 */  
        private Singleton() {  
        }  
      
        /* 此处使用一个内部类来维护单例 */  
        private static class SingletonFactory {  
            private static Singleton instance = new Singleton();  
        }  
      
        /* 获取实例 */  
        public static Singleton getInstance() {  
            return SingletonFactory.instance;  
        }  
      
        /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */  
        public Object readResolve() {  
            return getInstance();  
        }  
    }  

public class SingletonTest {  
 
    private static SingletonTest instance = null;  
 
    private SingletonTest() {  
    }  
 
    private static synchronized void syncInit() {  
        if (instance == null) {  
            instance = new SingletonTest();  
        }  
    }  
 
    public static SingletonTest getInstance() {  
        if (instance == null) {  
            syncInit();  
        }  
        return instance;  
    }  
} 


采用"影子实例"的办法为单例对象的属性同步更新,要不然要使用读者/写者的处理方式,设置一个读计数器,每次读取配置信息前,将计数器加1,读完后将计数器减1.只有在读计数器为0时,才能更新数据,同时要阻塞所有读属性的调用。:

public class GlobalConfig {
    private static GlobalConfig instance = null;
    private Vector properties = null;
    private GlobalConfig() {
      //Load configuration information from DB or file
      //Set values for properties
    }
    private static synchronized void syncInit() {
      if (instance = null) {
        instance = new GlobalConfig();
      }
    }
    public static GlobalConfig getInstance() {
      if (instance = null) {
        syncInit();
      }
      return instance;
    }
    public Vector getProperties() {
      return properties;
    }
    public void updateProperties() {
      //Load updated configuration information by new a GlobalConfig object
      GlobalConfig shadow = new GlobalConfig();
      properties = shadow.getProperties();
    }
  }


采用类的静态方法,和单例模式二者有什么不同?
首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)
其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。
再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。
最 后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。
但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联。

 

结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源

4 适配器模式 Adapter

类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。

对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。

接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。



5.装饰器模式 Decorator

装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例

应用场景:

5.1、需要扩展一个类的功能。

5.2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

缺点:产生过多相似的对象,不易排错!



6.代理模式 Proxy

应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

6.1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

6.2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!



7.外观模式 Facade

为了解决类与类之家的依赖关系。类关系被放在了另一个类之中,降低了类与类之间的耦合度,该模式中没有涉及到接口。



8.桥接模式 Bridge

把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。



9.享元模式 Flyweight

主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

FlyWeightFactory负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,FlyWeight是超类。





行为型模式:共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式.

第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类



10.策略模式 Strategy

定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。

策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。



11. 模板方法模式 Template Method

是指:一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用



12.观察者模式 Observer

当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。



13.迭代器模式 Iterator

顺序访问聚集中的对象,一般来说,集合中非常常见,包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。



14.责任链模式 Chain of Responsibility

,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。

此处强调一点就是,链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。



15. 命令模式 Command

目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开.



16. 备忘录模式 Memento

主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需 要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。



17. 状态模式 State

当对象的状态改变时,同时改变其行为

18.访问者模式 Visitor

是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。

该模式适用场景:如果我们想为一个现有的类增加新功能,不得不考虑几个事情:1、新功能会不会与现有功能出现兼容性问题?2、以后会不会再需要添加?3、 如果类不允许修改代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦,

19.中介者模式 Mediator

用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行