Headfirst设计模式 整理

来源:互联网 发布:淘宝联盟返利低 编辑:程序博客网 时间:2024/04/30 23:42

设计模式网址:

http://c2.com/cgi/wiki?WelcomeVisitors

http://hillside.net/

模式:是在某情境(context)下,针对某问题的某种解决方案。

反模式:告诉你如何采用一个不好的解决方案解决一个问题。

 

模式分类:

第一种分类:

1创建型: 创建型模式涉及到将对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦。

          Singleton, Abstract Factory, Factory Method,

          Prototype, Builder

2结构型:结构型模式可以让你把类或对象组合到更大的结构中。

          Decorator, Composite, Adapter, Facade, Proxy,

          Flyweight, Bridge

3行为型:只要是行为型模式都设计到类和对象如何交互及分配职责。

          Template Method, Command, Iterator, Observer,State, Strategy

         Mediator, Visitor, Interpreter, Chain of Responsibility,Memento

 

第二种分类

1.类:类模式描述类之间的关系如何通过继承定义。类模式的关系是在编译时建立的。

      Template Method, Factory Method, Adapter, Interpreter

2.对象:对象模式描述对象之间的关系,而且主要是利用组合定义。对象模式的关系通常在运行时建立,而且更加动态、更有弹性。

 

 

设计原则:

1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。P47

2. 针对接口编程,而不是针对实现编程。 P49

3. 多用组合,少用继承。P61

4. 为了交互对象之间的松耦合设计而努力。 P90

5. 开放-关闭原则:P123

类应该对扩展开放,对修改关闭。

6. 依赖倒置原则(Dependency Inversion): P176

要依赖抽象,不要依赖具体类。

7. 最少知识原则(Least Knowledge): P302

只和你的密友谈话。

8. 好莱坞原则: P333

别调用(打电话给)我们,我们会调用(打电话给)你。

9. 一个类应该只有一个引起变化的原因。P376

 

模式定义:

1策略模式(Strategy Pattern): 定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

 

2观察者模式(Observer Pattern):定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

注:可以使用Java内置的观察者模式

import java.util.Observable;

import java.util.Observer;

notifyObservers() “拉” 每个观察者要从被观察者中取数据

notifyObservers(Object arg) “推” 当通知时,此版本可以传送任何的数据对象给每一个观察者。

Observable是一个“类”,被观察者只能继承它,但是就不可以继承其他类了。

Observer是一个接口。

 

3装饰者模式(Decorator Pattern):动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。

注:装饰者可以在被装饰者的行为前面/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定目的。

你可以用无数个装饰者包装一个组件。但是装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

 

4工厂方法模式(Factory Method Pattern):定义了一个创建对象的接口,但由于子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

 

5抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

注:工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。

抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。

 

6单件模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。

注:经典的单件模式

public class Singleton {

    private static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance() {

       if (uniqueInstance == null) {

           uniqueInstance = new Singleton();

       }

       return uniqueInstance;

    }

}

但是如果是多线程的话,可能会生成两个实例。只要把getInstance()变成同步(synchronized)方法,但是会影响性能。而且只有第一次执行此方法时才真正需要同步。

改善多线程方法有3:

a)       如果getInstance()的性能对应用程序不是很关键,就什么都别做。

b)       使用“急切”创建实例,而不用延迟实例化的做法。

public class Singleton {

    private static Singleton uniqueInstance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {

       return uniqueInstance;

    }

}

c)       用”双重检查加锁”,在getInstance()中减少使用同步。

首先检查是否实例已经创建了,如果尚未创建,“才”进行同步。这样一来,只有第一次会同步。

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance() {

       if (uniqueInstance == null) {

           synchronized (Singleton.class) {

              if (uniqueInstance == null) {

                  uniqueInstance = new Singleton();

              }

           }

       }

       return uniqueInstance;

    }

}

 

7命令模式(Command Pattern):将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

命令模式更多的用途:队列请求,日志请求

 

8适配器模型(Adapter Pattern):将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

注:适配器有两种形式:对象适配器和类适配器。类适配器需要用到多继承。

 

9外观模式(Facade Pattern):提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

注:

a.       当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器;当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。

b.       适配器改变接口以符合客户的期望;外观将客户从一个复杂的子系统中解耦。

c.       适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。

 

 

 

10模块方法模式(Template Method Pattern):在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模块方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

注:

a.       策略模式和模板方法模式都封装算法,一个用组合,一个用继承。

b.       工厂方法是模板方法的一种特殊版本。

c.       钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它。常见的钩子如Sort算法中的CompareTo(),JFame中的paint(),Applet中的init(),start(),stop(),destroy()。

 

11迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

 

12组合模式(Composite Pattern):允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

 

13状态模式(State Pattern):允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

注:状态模式和策略模式有相同的类图,但是它们的意图不同。策略模式通常会用行为或算法来配置Context类。状态模式允许Context随着状态的改变而改变行为。

 

14代理模式(Proxy Pattern):为另一个对象提供一个替身或占位符以控制对这个对象的访问。

注:

远程代理管理客户和远程对象之间的交互;

虚拟代理控制访问实例化开销大的对象;

保护代理基于调用者控制对对象方法的访问。

代理还有很多变体,例如:缓存代理、同步代理、防火墙代理和写入时复制代理。

代理在结构上类似装饰者,但是目的不同。装饰者模式为对象加上行为,而代理则是控制访问。

 

 

**复合模式:复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题。

---------------------------------------------------------------------

15桥接模式(Bridge Pattern):使用桥接模式不只改变你的实现,也改变你的抽象。

注:

优点:将实现予以解耦,让它和界面之间不再永久绑定;

           抽象和实现可以独立扩展,不会影响到对方;

      对于“具体的抽象类”所做的改变,不会影响到客户。

用途和缺点:适合使用在需要跨越多个平台的图形和窗口系统上;

                            当需要用不同的方式改变接口和实现时,你会发现桥接模式很好用;

                            桥接模式的缺点是增加了复杂度。

 

16生成器模式(Builder Pattern):使用生成器模式封装一个产品的构造过程,并允许按步骤构造。

注:优点:将一个复杂对象的创建过程封装起来;

                       允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工厂模式不同)

                       向客户隐藏产品内部表现。产品的实现额可以被替换,因为客户只看到一个抽象的接口。

17责任链(Chain of Responsibility Pattern):当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。

注:优点:将请求的发送者和接受者解耦;

                     可以简化你的对象,因为它不需要知道链的结构;

                     通过改变链内成员或调用它们的次序,允许你动态地新增或者删除责任。

         用途:经常被使用在窗口系统中,处理鼠标和键盘这类的事情。

缺点:并不保证请求一定会被执行;如果没有任何对象处理它的话,它可能会落到链尾端之外。可能不容易观察运行时的特征,有碍于除错。

 

18蝇量模式(Flyweight Pattern):如想让某个类的一个实例能用来提供许多“虚拟实例”,就是用蝇量模式。

注:优点: 减少运行时对象实例的个数,节省内存。

                      将许多“虚拟”对戏那个的状态集中管理。

用途: 当一个类有去多实例,而这些实例能被同一方法控制的时候,就可以用~。

缺点: 一点你实现了~,那么单个的逻辑实例将无法拥有独立而不同的行为。

 

19解释器模式(Interpreter Pattern):为语言建解释器。

注:优点:将每一个语法规则表示成一个类,方便于实现语言;

                     因为语法由许多类表示,所以可以轻易改变或扩展此语言;

                     通过在类结构中加入新的方法,可以在解释的同时增加新的行为。

    用途:当需要实现一个简单的语言时;当你有一个简单的语法,而且简单比效率更重要时。可以用处理脚本语言和编程语言。

    缺点:当语法规则的数目太大时,这个模式可能会变得非常繁杂。在这种情况下,使用解析器/编译器的产生器可能更合适。

   

20中介者(Mediator Pattern):使用中介者模式来集中相关对象之间复杂的沟通和控制方式。

注:优点:通过将对象彼此解耦,可以增加对象的复用性。

                     通过将控制逻辑集中,可以简化系统维护。

          可以让对象之间所传递的消息变得简单而且大幅减少。

 

21备忘录模式(Memento Pattern):当你需要让对象返回之前的状态(例如你的用户请求“撤销”),就是用备忘录模式。

注:优点:将被储存的状态放在外面,不要和关键对象混在一起,可提高内聚性;

                     保持关键对象的数据封装;

              提供了容易实现的恢复能力。

用途:用于储存状态。

缺点: 储存和恢复状态的过程可能相当耗时。

在Java系统中,其实可以考虑使用序列化机制储存系统的状态。

 

22原型模式(Prototype Pattern): 当创建给定类的实例过程很昂贵或很复杂时,就是用原型模型。

注:优点:向客户隐藏制造新实例的复杂性;

                     提供让客户能够产生未知类型对象的选择;

                     在某些环境下,复制对象比创建新对象更有效。

用途:在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑~。

缺点:对象的复制有时相当复杂。

 

23访问者(Visitor Pattern): 当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。

注:优点:允许你对组合结构加入新的草走,而无需改变结构本身;

                     想要加入新的操作,相对容易;

          访问者所进行的操作,其代码是集中在一起的。

缺点:打破组合类的封装;

      因为游走的功能牵涉其中,所以对组合结构的改变就更加困难。