存档Head First Design Patterns

《Head First Design Patterns》-第十一章

在RMI中,客户端的帮助类称为stub,服务器端的帮助类称为skeleton。
RMI:
第一步:构建远程接口。服务接口需要继承Remote接口,并声明其中所有的方法抛出RemoteException,确认所有的参数和返回值都是可序列化的。
第二步:构建远程实现。实现远程接口的类需要扩展UnicastRemoteObject,添加声明了RemoteException的无参数构造方法,把服务注册到RMI registry中,使用Naming.rebind。
第三步:生成stubs和skeletons。对远程实现类使用rmic。
第四步:运行rmiregistry。
第五步:启动服务。运行远程实现类。

客户端运行Naming.lookup,RMI registry返回stub对象,RMI自动反序列化该对象,因此你在客户端需要stub类,客户端调用stub的方法,就好像stub是实际的服务一样。

客户端需要的类是stub和远程接口类;服务端需要远程接口类,远程实现类,生成的stub和skeleton。

The Proxy Pattern provides a surrogate or placeholder for another object to control access to it.

虚拟代理是作为创建代价昂贵的对象的表示。虚拟代理通常直到真正需要才会创建对象,一旦创建出来,它把所有的请求代理给实际的对象。

代理模式变种的共同之处在于拦截客户端对subject的方法调用。

JDK的动态代理
第一步:构建Invocation Handlers。InvocationHandler只有一个方法invoke。
第二步:构建Proxy类并实例化Proxy对象。使用Proxy.newProxyInstance来创建代理。

可以使用Proxy.isProxyClass()来判断一个类是否是动态代理类。Proxy.newProxyInstance()只能接受接口数组,而不是类。所有的非公共接口需要来自同一个包,不能有包含冲突方法的接口。从JDK1.2开始就不需要skeleton了。在JDK 5中,stub也不需要了,可以使用动态代理来动态生成。

评论(1)

《Head First Design Patterns》-第十章

The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

State Pattern 和Strategy Pattern的类图比较类似,它们的区别在于意图不同。
使用State Pattern,把一系列的行为封装在状态对象中,任何时刻context代理给其中的一种状态。随着时间,当前的状态会在一系列状态对象中变化以反映context的内部状态,从而context的行为也发生变化。但是client通常并不知道这些状态对象。
使用Strategy Pattern,client通常需要指定context需要组合的strategy对象。
可以把Strategy Pattern看成是继承的一种灵活的替代。使用Strategy,你可以通过组合另外一个对象来改变行为。
把State Pattern看成是在context中放置很多条件判断的替代。通过把行为封装在状态对象中,可以通过改变context中的状态对象来改变其行为。

需要权衡的是由context还是状态对象来确定下一个状态。通常情况下,如果状态转换是固定的,放在context中比较合适;如果转换是动态的,最好放在状态类中。把状态转换放在状态类中的不足是各个状态类之间有了依赖。

Client不直接与状态进行交互。如果有多个context的话,可以共享状态对象。

留言

《Head First Design Patterns》第九章

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

External iterator指客户端通过调用next来控制迭代的过程;internal iterator是由迭代器自己控制的,你需要告诉迭代器在迭代的时候如何处理元素,即传递一个操作给迭代器。

Single Responsibility Principle: A class should have only one reason to change.

The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

使用Composite Pattern时需要考虑的一个设计tradeoff是客户端是否应该知道一个元素是叶子节点还是组合节点。如果客户端不知道的话,会丧失一部分类型安全性;如果知道的话,则丧失了透明性,而且客户端需要使用instanceof的条件语句。

留言

《Head First Design Patterns》第八章

The Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

钩子是指定义在抽象类中的方法,但是只有空的或是默认的实现。这使得子类在不同的hook into到算法中来。钩子的作用在于提供一种子类实现可选部分的方法;使得子类有机会对模板方法中将要发生或已经发生的某些步骤做出反应;使得子类能为抽象类做决定。

创建了一个模板方法之后,如果子类必须提供实现的话,则使用抽象方法;如果是可选的话,则使用钩子。

Hollywood Principle: Don’t call us, we’ll call you.

好莱坞原则使得我们可以防止dependency rot;使用该原则,使得低层组件hook到系统中来,但是由高层组件来确定什么时候和什么方式下它们是需要的。

依赖反转原则告诉我们避免使用具体类,而是尽可能的使用抽象。好莱坞原则是构造框架或组件的技术,使得低层组件可以hook到计算中来,却不会在低层组件和高层层次中增加依赖。它们的作用都是解耦,不过依赖反转原则提供了如何避免依赖的更强大和更普遍的说明。好莱坞原则使得低层结构能够互操作,同时防止其它类过分依赖它们。

模板方法模式和策略模式的不同在于,模板方法只是实现了不完整的算法,需要子类来提供部分实现;而策略模式组合的是整个算法的实现。模板方法是通过组合的,而策略模式是通过继承。

工厂方法是模板方法的特例。

留言

《Head First Design Patterns》第七章

实现一个adapter的工作量和目标接口的大小成正比的。

The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

存在两类adapter,分别是class adapter和object adapter,class adapter只有在支持多继承的语言中才可以使用,是让Adapter继承Target和Adaptee。

The Facade Pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

Principle of Least Knowledge – talk only to your immediate friends.
该原则告诉我们只应该调用如下的方法:对象本身的;作为参数传递进来的对象的;该方法创建的对象的;该对象的组件的。

应用这一规则的不好方面是导致过多的处理对其他组件方法调用的wrapper类,从而增加复杂度和开发时间,降低运行时的性能。 

留言

《Head First Design Patterns》第六章

Command Pattern用来封装方法调用,解耦动作的调用者和动作的实际执行对象。

The Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.

The Meta Command Pattern允许你创建命令的宏,从而可以一次执行多个命令。

Null Object:当你没有一个有意义的对象可以返回,但是又不希望由客户端来处理null的时候,可以使用一个null object。

通常情况下,我们使用的dumb command object,它的作用仅是调用接收者上的一个动作;当然也存在smart command object,它实现了执行请求所需要的一些逻辑。如果这样的话,调用者和接收者之间的解耦层次就不一样了,也不能用命令来参数化接收者了。

可以使用Command Pattern来queuing requests;有些应用需要记录下所做的全部操作,并能够在崩溃之后重新执行这些操作。通过logging,可以保存自上一个check point以来所作的所有操作,如果系统崩溃的话,自check point开始重新执行这些操作就可以。

留言

《Head First Design Patterns》第五章

Singleton Pattern是确保有而且只有一个给定的类的实例的惯用法。它同样提供一个全局的访问点。
经典的Singleton Pattern的实现方法:
public class Singleton {
  private static Singleton uniqueInstance;
  private Singleton() {}
  public static Singleton getInstance() {
if (uniqueInstance == null) {
  uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}

The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.

经典的Singleton实现在多线程情况下是有问题的。最简单的解决办法就是给getInstance方法加上synchronized。不过这会影响性能,因为一旦uniqueInstance被实例化之后,同步就没有任何意义了。解决性能问题有几个办法,如果getInstance的性能不是那么关键的话,可以不去管它;如果你的应用总是需要创建和使用Singleton的实例或者Singleton的创建和运行时刻的代价不是很大的话,可以采用预先初始化的方法。采用double-checked locking来减少对getInstance的同步:
public class Singleton {
  private volatile static Singleton uniqueInstance;
  private Singleton() {}
  public static Singleton getInstance() {
if (uniqueInstance == null) {
    synchronized (Singleton.class) {
    uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
需要注意的是double-checked locking在Java 1.4以及之前的版本中是不起作用的。

注意有可能两个classloader可能每个都创建自己的Singleton实例。每个classloader定义了一个namespace,如果有多个classloader的话,可能多次加载同一个类。如果使用多个classloader和Singleton的话,要注意。一种办法是自己指定classloader。

留言

《Head First Design Patterns》第四章

所有的工厂模式都封装对象的创建。Factory Method Pattern通过让子类来决定创建什么对象来进行封装。
The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

依赖反转原则:依赖于抽象而不是具体的类。高层的组件不应该依赖于低层的组件,它们都应该依赖于抽象。
遵循依赖反转原则的指南:
1. 没有变量是引用具体类的。
2. 没有类是继承自具体类的。
3. 没有方法覆写基类中已经实现的方法。
当然,以上这些只是指导原则,实际是很难这么做的。重要的是设计的时候把这些指南放在脑中,当你要违反的时候,你就有足够的理由。

The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.

BULLET POINTS
所有的工厂都封装对象的创建。
工厂方法依靠继承:对象的创建是代理给实现了工厂方法的子类。
抽象工厂依靠对象组合:对象的创建是实现在工厂接口暴露的方法中的。
所有的工厂模式通过减少应用对具体类的依赖来降低耦合。
工厂方法的意图是使得类把对象的实例化推迟到其子类。
抽象工厂的意图是创建相关对象家族而不需要依赖于它们具体的类。
依赖反转原则指导我们避免依赖于具体的类。
工厂是对抽象而不是具体类编程的强大技术。

留言

《Head First Design Patterns》第三章

Classes should be open for extension, but closed for modification.

Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

BULLET POINTS
继承是扩展的一种方式,但不一定是在设计中达到灵活性的最好方式。
在设计中需要不修改已有代码来扩展行为。
组合和代理通常用来在运行时刻增加行为。
Decorator Pattern提供了除了继承之外的另外一种扩展行为的方式。
Decorator Pattern包括用来包装具体组件的装饰器类。
装饰器类的类型和被它们装饰的组件一样。
装饰器类通过在调用所装饰的组件的方法之前或之后增加新功能来改变组件的行为。
可以给组件任意数量的装饰器。
装饰器通常对组件的使用者是透明的;除非组件的使用者依赖于具体的组件类型。
装饰器可以导致设计中的过多的小类,过分的使用会增加复杂度。
我自己写的例子,源码下载

decorator.JPG

留言

《Head First Design Patterns》第二章

这一章是关于Observer模式的。

Publishers + Subscribers = Observer Pattern

The Observer Pattern defines a one-to-many dependency between objects so that when on object changes state, all of its dependents are notified and updated automatically.

尽力实现交互对象之间松散耦合的设计。

松散耦合的设计使得我们可以构建适应变化的灵活的OO系统,因为它最小化了对象之间的相互依赖。

使用Java内建的Observer Pattern
某个对象要成为observer的话,实现Observer接口,在任何Observable对象上调用addObserver方法,同样可以使用deleteObserver来把自己删除。
Observable要发送通知的话,首先调用setChanged方法来声明状态已经发生变化,接着调用两个方法中的一个:notifyObservers() 和notifyObservers(Object arg)。
Observer要接收通知的话,它实现了update方法,update(Observable o, Object arg)。如果你希望往观察者推送数据的话,可以把数据作为对象传过去;如果不是,那么观察者需要自己从Observable对象中拉数据。
方法setChanged的作用在于你可以通过优化通知的频率来灵活的控制对观察者的更新。

不要依赖于Observer通知的执行顺序。

java.util.Observable的不好的地方
Observable是类不是接口。因此你只能继承它,从而无法再继承其他的类了;由于Observable不是接口,所以你无法提供自己的实现。
Observable保护了重要的方法,其中的setChanged是受保护的,也就是说你只能继承Observable才能调用该方法,也就不能使用组合了。
 

我自己写了一个简单的Observer模式的例子,代码下载

Observer模式例子截图

留言

« Previous entries