《headfirst设计模式》笔记

总结

基础

抽象

封装

多态

继承

原则

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程

为交互对象之间的松耦合设计而努力

对扩展开放,对修改关闭

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

只和朋友交流

别找我,我会找你

类应该只有一个改变的理由

模式

策略模式

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

观察者模式

在对象之间定义一对多的依赖,这样一来,当这个对象改变状态,依赖它的对象都会受到通知,并自动更新。代表MVC

装饰者模式

动态将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。代表JAVA中IO(INPUTStream系列)

抽象工厂模式

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

工厂方法模式

定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

单例模式

确保一个类只有一个实例,并提供全局访问点。

命令模式

将请求封装成对象,这可以让你使用不同的请求、队列、或者日志请求来参数化其对象。命令模式也可以支持撤销操作

适配器模式

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

外观模式(门面模式)

提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更加容易使用。

模板方法模式(Template)

在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使的子类可以在不改变算法的结构的情况下,重新定义算法中的某一些步骤。

迭代器模式(Iterator)

提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露其内部的表示

组合模式(Composite)

运行你将对象组成树形结构表现“整体/部分”的层次结构。组合能让客户以一致的方式处理个别对象和对象组合。

状态模式(STATE)

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类

代理模式(proxy)

为另一个对象提供一个替身或占位符以访问这个对象

复合模式

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

设计模式入门

使用模式对的最好方式:把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用他们。

  1. 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。针对接口编程,就是针对超类型编程。
  3. 变量的声明应该是超类型:比如抽象类或者一个接口。
  4. 有一个(组合)可能比是一个更好
  5. 多用组合,少用继承.类的行为不是通过继承得到而是通过组合得到的。

策略模式(Strategy)

定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

类的行为就可以看做是算法

观察者模式(Observe)让你的对象知悉现况

类比报纸、杂志的订阅

观察者模式

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
Swing大量使用观察者模式,许多GUI框架也是如此。

java内置观察者模式

JAVA API有内置的观察者模式。java.util包内包含了最基本的Observer接口与Observable类,甚至可以使用推拉模式。

可观察者如何送出通知

  1. 先调用setChanged()方法,标记状态已经改变的事实
  2. 然后调用两种notifyObservers()方法中的一个:notifyObservers()或notifyObservers(Object arg),这个版本可以传送任何数据对象给每一个观察者

观察者如何接受通知

观察者实现了更新方法,但是方法的签名不一样。

update(Observable o,Object arg)
1. Observable:主题本身当做第一个变量,好让观察者知道是哪个主题通知它的。
2. arg这正是传入notifyObservers()的数据,如果没有说明则为空

setChanged()方法用来标记状态已经改变的事实,好让notifyObservers()知道当它被调用时应该更新观察者。如果调用notifyObservers()之前没有先调用setchanged(),观察者就不会被通知。

java.util.Observable的暗黑面
Observable是以类,不是接口,必须被继承。
setChanged()方法是protect的,只有继承才能调用。

装饰者模式(Decorator)

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

举例:以饮料为主体,然后运行时以调料来“装饰”饮料。

  1. 装饰者和被装饰者对象有相同的超类型。
  2. 你可以用一个或多个装饰者包装一个对象
  3. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为
  4. 对象可以在任何时候被装饰

装饰者模式

动态地将责任附加到对象上,若有拓展功能,装饰者提供了比继承更有弹性的替代方案。
真实世界的装饰者:java I/O

装饰者模式缺点

有大量的小类,数量比较多

原则

对拓展开放,对修改关闭

工厂模式(Factory)

利用静态方法定义一个简单的工厂,这是很常见的技巧,常被称为静态工厂。为何使用静态方法?因为不需要使用创建对象的方法来实例化对象。但是有一个缺点,不能通过继承来改变创建方法的行为

定义简单工厂

简单工厂其实不是一个设计模式,应该算是一种编程习惯。
设计模式中,所谓“实现一个接口”并不一定表是写一个类,并利用implement关键字来实现某个Java接口。“实现一个接口”泛指实现某个超类型(可以试类或接口)

所有工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

定义工厂方法模式

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

简单工厂把全部的事情,在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定要如何实心。简单工厂的做法,是将对象的创建封装起来,简单工厂不具备工厂方法的弹性。

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

多依赖抽象类,而不依赖具体类。
依赖倒置:是底层组件依赖于抽象高层的抽象。

定义抽象工厂模式

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

总结

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

  1. 所有的工厂都是用来封装对象的创建
  2. 简单工厂,虽然不是真正的涉及模式,但是也是一个简单的方法,实现将客户程序从具体类解耦
  3. 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
  4. 抽象工厂使用对象的组合:对象的创建被实现在工厂接口所暴露出来的方法中
  5. 抽象工厂创建相关的对象家族,而不需要依赖它们具体类。
  6. 简单理解就是抽象工厂由多个工厂方法组成

单例模式(singleton)

用来创建独一无二的,只能有一个实例的对象。比如线程池、内存、配置表。

单例模式也提供一个全局访问点,和全局变量。但是不是程序一开始就创建对象。
JVM实现:在用到的时候才创建对象

经典的单间模式实现

public class Singleton{
    private static Singleton uniqueInstance;//利用静态变量记录唯一实例
    private Singleton(){//私有构造器声明为私有,只有Singleton类才可以调用构造器
        
    }
    public static Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
    
}

如果我们不需要这个实例,它就永远不会产生

单例模式

确保一个类只有一个实例,并提供一个全局访问点

处理多线程问题

把getInstance()变成同步(synchronized)方法,就可以解决多线程

public class Singleton{
    private static Singleton uniqueInstance;
    private Singleton(){}
    public static synchronized Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqeuInstance;
    }
}

诚然,这种方式会影响性能。可以有如下选择:

  1. 如果getInstance()的性能对应用程序不是很关键,就什么都别做。这样做简单高效
  2. 如果创建单例,对程序负担不重,就不用延迟实例化的做法
pulbic static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
    return uniqueInstance;
}
  1. 用双重检查加锁,在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;
    }
}

注意:volatile关键字确保:当uniqueInstance变量被初始化,多个线程能处理uniqueInstance变量。必须在1.5及以上才能使用。

关于多个类加载器可能有机会各自创建自己的单价实例

每个类加载器都定义了一个命名空间。如果有两个以上的类加载器,不同的类加载器可能会加载同一个类,从整个程序来看,同一个类会被加载多次。如果是单例模式的类,就会产生多个单例并存。解决办法:自行指定类加载器,并指定同一个类加载器。

java1.2以后单例模式不会被垃圾回收器回收。放心使用

总结

  1. 单例模式确保程序中一个类最多只有一个实例
  2. 单例模式也是提供访问这个实例的全局点
  3. 在java实现单例模式需要私有构造器、一个静态方法和一个静态变量
  4. 确定在性能和资源的限制上,小心选择适当的方案来实现单例。
  5. 如果不是采用java 5以上,双重检查会失效。
  6. 使用JVM1.2或之前的版本,必须建立单件注册表,以免垃圾收集器将单件回收

命令模式(command)——封装调用

将方法调用(method invocation)封装起来
通过封装方法调用哦,可以记录日志、或者实现撤销undo
命令模式可以将“动作的请求者”从“动作的执行者”对象中解耦

命令模式

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

在许多设计模式中都会看到空对象的使用。甚至有些时候,空对象本身也被视为是一种设计模式

总结

  1. 命令模式将发出请求的对象和执行请求的对象解耦
  2. 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者的一个或一组动作
  3. 调用者通过调用命令对象的excute()发出请求,这会使得接受者的动作被调用
  4. 调用者可以接受命令当做参数,甚至在运行时动态地进行
  5. 命令可以支持撤销,做法是实现一个undo()方法来回到excute()被执行前的状态。
  6. 宏命令是命令的一种简单延伸,允许调用多个命令。宏方法也可以支持撤销
  7. 实际操作时,很常见使用命令对象,也可以直接实现请求,而不是将工作委托给接受者。
  8. 命令可以用来实现日志和事物系统。

适配器模式(Adapter)与外观模式(Facade,也叫门面模式)

装饰者模式将对象包装起来,并赋予它们新的职责。而现在是将某些对象包装起来,将类的接口转换成自己想要的接口

需要让一个适配器包装多个被适配者,这就是外观模式

定义适配器模式

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

1. 类适配器使用多重继承,对象适配器使用组合
2. 对象适配器使用组合,可以适配该类的任何子类
3. 

装饰者和适配器

  1. 当事情涉及到装饰者,就表示一些新的行为或责任要加入到你的设计中。
外观模式和适配器模式的差异不在于它们包装了几个类,而是在于它们的意图,适配器模式的意图是“改变”接口符合客户的期望;而外观模式的意图是提供子系统的一个简化接口。

定义外观模式

提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

最少知识原则

告诉我们要减少对象之间的交互,只留下几个密友

总结

  1. 当需要使用一个现有的类而其接口不符合我的需求时,就使用适配器
  2. 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观
  3. 适配器改变接口以符合客户的期望
  4. 外观将客户从一个复杂的子系统中解耦
  5. 实现一个适配器可能需要一番功夫,与目标接口的大小和复杂程度有关
  6. 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统来执行
  7. 适配器模式有两种形式:对象适配器和类适配器。类适配器需要用到多重继承
  8. 你可以为一个子系统实现一个以上的外观
  9. 适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任,而外观将一群对象“包装”起来以简化接口。

模板方法模式 封装算法(Template)

直到目前,我们议题都绕着封装转;我们已经封装了对象的创建、方法的调用、复杂接口。接下来我们要封装算法块

模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现

定义模板方法模式

在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使的子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤

1. 当你的子类必须提供算法中的某个方法或步骤的实现时,就使用抽象方法。如果算法的这个部分是可选的,就使用钩子,如果是钩子的话,子类可以选择实现这个钩子
2. 好莱坞法则:别调用高层,让高层选择调用
3. applet大量使用了模板方法模式

总结

  1. 模板方法定义了算法的步骤,把这些步骤的实现延迟到了子类
  2. 模板方法模式为我们提供了一种代码复用的重要技巧。
  3. 模板方法的抽象类可以定义具体方法、抽象方法和钩子
  4. 抽象方法由子类实现
  5. 钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它
  6. 为了防止子类改变模板方法中的算法,可以将模板方法声明为final
  7. 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用底层模块
  8. 策略模式和模板方法模式都封装算法,一个用组合一个用继承
  9. 工厂方法是模板方法的一种特殊版本

管理良好的集合 迭代器(Iterator)与组合模式(Composite)

封装变化的部分

1. 如果不允许一个方法,可以抛出一个java.lang.UnsupportedOperationException运行时异常

定义迭代器模式

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式把元素之间的游走的责任交给迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得更简洁,也可以让聚合更专注在它所应该专注的事情上面

迭代器意味着没有次序。只是取出所有的元素,并不表示取出元素的先后就代表元素的大小次序。对于迭代器来说,数据结构可以有次序或是没有次序,甚至数据是可以重复的。除非某个集合文件有特别说明,否则不可以对迭代器所取出的元素大小顺序做出假设

单一责任

类的每个责任都有改变的潜在区域。超过一个责任,意味着超过一个改变的区域。这个原则告诉我们,尽量让每个类保持单一责任

#### java5的迭代器和集合
java5中包含了一种新形式的for语句,称为for/in.这可以让你在一个集合或者一个数组中遍历,而且不需要显式创建迭代器
```
for(Object:collection){
    
}
```

定义组合模式(composite)

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

使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别

总结

  1. 迭代器允许访问聚合的元素,而不需要暴露它的内部结构
  2. 迭代器将遍历聚合的工作封装进一个对象中。
  3. 当使用迭代器的时候,我们依赖聚合提供遍历
  4. 迭代器提供了一个通用的接口,让我们遍历聚合的项时,就可以使用多态机制
  5. 组合模式提供一个结构,可同时包容个别对象和组合对象
  6. 组合模式允许客户对个别对象以及组合对象一视同仁
  7. 组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点

状态模式(事物的状态)state

状态通过改变对象内部的状态来帮助对象控制自己的行为

定义状态模式

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类

将状态封装称为独立的类,并将动作委托到代表当前状态的对象,我们知道行为会随着内部状态而改变

总结

  1. 状态模式允许一个对象基于内部状态而拥有不同的行为
  2. 和程序状态机PSM不同,状态模式用类代表状态
  3. Context会将行为委托给当前状态对象
  4. 通过将每个状态封装进一个类,我们把以后需要做的任何改变发局部化了
  5. 状态模式和策略模式有相同的类图,但是它们的意图不同
  6. 策略模式通常会用行为或算法来配置Context类
  7. 状态模式允许Context随着状态的改变而改变行为
  8. 状态转换可以由STATE类或Context类控制
  9. 使用状态模式通常会导致设计中类的数目大量增加
  10. 状态类可以被过个Context实例共享

代理模式(Proxy)控制对象的访问

代理要做的就是:控制和管理访问
远程对象:是一种对象,活在不同java虚拟机(JVM)堆中或者说,在不同的地址空间运行的远程对象

制作远程服务

  1. 制作远程接口 远程接口定义出可以让客户远程调用的方法
  2. 制作远程实现 为远程接口中定义远程方法提供真正的实现
  3. 利用rmic产生的stub和skeleton。这是客户和服务的辅助类,不需要创建这些类
  4. 启动RMI registry 可以从中查找代理的位置
  5. 开始远程服务 服务实现类去实例化一个服务的实例,并将这个服务注册到RMI registry

制作远程接口

  1. 拓展java.rmi.Remote remote不具有方法,只是一个标记
  2. 声明所有的方法都会抛出RemoteException
  3. 确定变量和返回值属于原语类型或者序列化类型。远程方法的变量和返回值,必须属于原语类型或Serializable类型。这不难理解。远程方法的变量必须被打包并通过网络运送,这要靠序列化来完成。如果你使用原语类型、字符串和许多API中内定的类型,都不会有问题。如果你传送自己定义的类,就必须保证你的类实现了Serializable

制作远程实现

  1. 实现远程接口 你的服务必须实现远程接口,也就是客户将要调用的方法接口
  2. 拓展UnicastRemoteObject 为了要成为远程服务对象,你的对象需要某些“远程”功能。最简单的就是拓展UnicastRemoteObject,让超类帮你做这些工作
  3. 设计一个不带变量的构造器,并声明RemoteException
  4. 用RMI REgistry注册此服务 当注册这个实现对象时,RMI系统其实注册的是stub,因为这是客户真正需要的。注册服务使用了java.rmi.Naming类的静态rebind()方法

产生Stub和Skeleton

在远程实现类上执行rmic
rmic 是JDK内一个工具,用来为一个服务类产生stub和skeleton。

执行remiregistry

开启一个终端,启动remiregistry

启动服务

开启另一个终端,启动服务

工作方式

  1. 客户到RMI registry中寻找
Naming.lookup("rmi://127.0.0.1/RemoteHello")
  1. RMI registry返回Stub对象 作为lookup方法的返回值,然后RMI会自动对Stub反序列化。你在客户端必须有stub类,否则stub就无法被反序列化
  2. 客户调用stub的方法,就像stub就是真正的服务对象一样
注意:
1. 忘了在启动远程服务之前先启动rmiregistry
2. 忘了让变量和返回值的类型成为可序列化的类型
3. 忘了给客户提供stub类

transient关键字,这样就告诉JVM不要序列化这个字段

定义代理模式

为另一个对象提供一个替身或占位符以控制对这个对象的访问。
控制访问是客户端不知道如何访问真正的对象。

几种代理控制访问的方式
1. 远程代理控制访问远程对象
2. 虚拟代理控制访问创建开销大的资源
3. 保护代理基于权限控制对资源的访问

虚拟代理作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。

使用JAVA API代理创建保护代理

java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。动态代理,需要执行方法放在InvocationHandler中。

要点

  1. 代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种
  2. 远程代理管理客户和远程对象之间的交互
  3. 虚拟代理控制访问示例化开销大的对象
  4. 保护代理基于调用者控制对对象方法的访问
  5. 代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理和写入时复制代理
  6. 代理在结构上类似装饰者
  7. 装饰者模式为对象加上行为,而代理则是控制访问
  8. java内置的代理支持,可以根据需要建立动态代理,并将所有调用分配到所选的处理器
  9. 和其他的包装者(wrapper)一样,代理会造成你的设计中类的数目增加

复合模式 模式的模式

由不同模式构成模式。复合模式代表是MVC
复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。
MVC是数个模式的结合

MVC模式

  1. 模型利用观察者让控制器和视图可以随最新的状态改变而更新。控制器是视图的行为
  2. 视图和控制器实现了经典的策略模式:视图是一个对象,可以被调整使用不同的策略,而控制器提供了策略。
    Model 2是MVC在WEB上的调整

总结

  1. mvc是复合模式,结合了观察者模式、策略模式和组合模式
  2. 模型使用了观察者模式,以便观察者更新,同时保持两者之间的解耦
  3. 控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为
  4. 视图使用组合模式实现用户界面,用户界面通常组合了嵌套的组件,像面板、框架和按钮
  5. 这些模式携手合作,把MVC模型的三层解耦,保持设计干净又有弹性
  6. 适配器模式用来将新的模型适配成已有的视图和控制器
  7. model2是MVC在web上的应用,在model2中,控制器实现成Servlet,而JSP/html是视图

复合模式

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

与设计模式相处——真实世界中的模式

模式

在某情景下,针对某问题的某种解决方案

  1. 情景就是应用某个模式的情况,这应该是会不断出现的情况
  2. 问题就是你想在某情景下达到的目标,但也可以是某情景下的约束
  3. 解决方案就是你所追求的,一个通用的设计。

创建型模式

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

行为型模式

都涉及到类和对象如何交互及分配职责

结构型模式

可以让你把类或对象组合到更大的结构中

保持简单

设计时,尽可能用最简单的方式解决问题,你的目标应该是简单

重构的时间就是模式的时间

重构就是通过改变你的代码来改进它的组织方式的过程。目标是要改善其结构而不是其行为。应该将思绪集中在设计本身,而不是模式上,只有真正需要时才使用模式,有些时候简单的方式就行得通,那么就不要用模式

反模式

告诉你如何采用一个不好的解决方案解决一个问题。反模式看起来总像是一个好的解决方案,但是当它真正被采用后,就会带来麻烦。通过将反模式归档,我们能够帮助其他人在实现它们之前,分辨出不好的解决方案。
反模式有它自己的诱惑,但是在长远来看会造成不好的影响。反模式除了告诉你不好之外,也给你提出建议的解决方案。

  1. 模式能够带来最大的好处之一是:让你的团队拥有共享词汇。

其它模式

桥接模式(Bridge)

使用桥接模式不只改变你的实现,也改变你的抽象

责任链模式(Chain of Responsibility Pattern)

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式

享元模式(蝇量模式 Flyweight Pattern)

如想让某个类的一个实例能用来提供许多“虚拟实例”,就使用享元模式。
享元模式的用途和缺点

  1. 当一个类有许多的实例,而这些实例能被同一方法控制的时候,我们就可以使用享元模式
  2. 享元模式的缺点在于,一旦你实现了它,那么单个逻辑实例将无法拥有独立而不同的行为。

中介者 (Mediator pattern)

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

中介者的优点
1. 通过将对象彼此解耦,可以增加对象的复用性
2. 通过将控制逻辑集中,可以简化系统维护
3. 可以让对象之间所传递的消息变得简单而且大幅减少
中介者的用途和缺点
1. 中介者常常被用来协调相关的GUI组件
2. 中介者模式的缺点是,如果设计不当,中介者对象本身会变的过于复杂

备忘录(Memento Pattern)

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

备忘录的用途和缺点
1. 备忘录用于存储状态
2. 使用备忘录的缺点:存储和恢复状态的过程可能相当耗时
3. 在java系统中,其实可以考虑使用序列化机制存储系统的状态

原型模式(prototype)

当创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式

访问者模式

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

访问者的优点

1. 允许你对组合结构加入新的操作,而无需改变结构本身。
2. 想要加入新的操作,相对容易
3. 访问者所进行的操作,其代码是集中在一起的

访问者的用途和缺点

1.  当采用访问者模式的时候,就会打破组合类的封装
2.  因为游走的功能牵涉其中,所以对组合结构的改变就更加困难

你可能感兴趣的:(学习笔记)