前段时间看了Head First设计模式,写了些记录。
策略模式(Strategy)
策略模式定义
定义算法簇,分别封装起来,让他们之间可以互相替换,让算法的变化独立与使用算法的客户
1. 利用接口,抽象类
从类中抽象出共同的行为,组合成一种行为接口
2. 找出应用中可能变化的地方,把他们独立出来,和稳定的代码区分开
3. 针对接口编程,而非针对实现编程
类中包含行为,但不需要直接实现行为。通过行为接口具体的实现,运行时选择
4. 封装行为,has比is好;多用组合,少用继承
代码:
public interface SomeBehavior{
public void doSomething();
}
public class DoOne implements SomeBehavior{
public void doSomething(){
//do something
}
}
public class DoTwo implements SomeBehavior{
public void doSomething(){
//do something
}
}
public abstract class BaseClass{
private SomeBehavior someBehavior;
public void doBehavior(){
someBehavior.doSomething();
}
}
//以下可以继承其他具体类
public class UseClass extends BaseClass{
public UseClass(){
someBehavior=new DoOne();
}
//doBehavior();//已经是DoOne的行为
}
观察者模式(Observer)
观察者模式定义了对象之间的一对多依赖,当一个对象改变状态是,他的所有依赖者都会收到通知并自动更新。
观察者模式类图:
《interface》—————————–>《interface》
Subject Observer
registerObserver() update()
removeObserver() |
notifyObserver() |
| |
| |
ConcreteSubject ConcreteObserver
registerObserver() update()
removeObserver()
notifyObserver()
getState()
SetState()
代码:
//订阅者
public interface Subject{
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
//观察者
public interface Observer{
public void update();
}
具体类的实现可以通过ArrayList进行Observer的添加,维护和删除。具体的Observer的update可以根据具体的情况实现。
观察者模式有两种通知更新方式:
分发和获取。即更新的方式为被动和主动两种方式。
被动方式即通过notifyObserver()方式实现,遍历Observer列表顺序更新。
主动方式则是根据Observer的需要适时的向Subject进行更新请求,获取最新的数据。
Observer模式的应用:按钮的注册和事件分发。消息队列。
装饰者模式(Decorator)
当实体类过多时,继承可能可以解决问题,但是发生变动时会产生很多问题,基类加入的新功能并不适合所有子类。
类应该对扩展开放,对修改关闭。
装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更具有弹性的替代方案。
装饰者Decorator继承自基类Component并包含一个Component用以保存具体Component实例。事实上通过组合可以减少继承使用的而生成的子类的个数。
缺点:使用者可能不能够理解大量的小类是通过包装实现。依赖特定的类型,从而出现错误。
工厂模式(Factory)
当需要实例化一个具体的类时,就会用到new。但是因此代码缺少了降低变化的可能性。
简单工厂:将创建实例的过程移到一个实例工厂里。让客户与具体的实例化代码解耦。
工厂方法:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法把实例化推迟到子类。
抽象工厂:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类。
抽象工厂是生产一系列相关类,强调的是有关系。
所有工厂模式都用来封装对象的创建。
代码示例:
简单工厂
public class Factory{
public static Sample creator(int which){
//getClass 产生Sample 一般可使用动态类装载装入类。
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
Sample sampleA=Factory.creator(1);
抽象工厂
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA;
}
public Sample2 creator(String name){
.........
return new Sample2A;
}
}
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB;
}
public Sample2 creator(String name){
......
return new Sample2B;
}
}
单件模式(Singleton)
单件模式:确保一个类只有一个实例,并提供一个全局访问点。
public class SampleClass{
private static SampleClass sample;
private SampleClass(){};
public static SampleClass getInstance(){
if(sample==null){
sample=new SampleClass();
}
return sample;
}
}
问题:处理多线程可能出现多个实例。
处理办法:
1、加synchronized修饰。
2、急切模式,在声明sample是就实例化变量private static SampleClass sample=new SampleClass();
命令模式(Command)
重点是解耦,连设计程序的时候可以多想一想每个类的作用从而设计其功能,尽量可以流水作业,独立解耦。
“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。
Command:
定义命令的接口,声明执行的方法。
ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
模式分析:
1.命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
2.每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
3.命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
4.命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
5.命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
适用环境 :(远程API?)
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起(配合多线程),即支持宏命令。
状态模式(State)
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态被封装成独立的类,通过状态机进行状态切换。
类图和策略模式相同,但是在context中的setstate方法可以被具体状态调用从而在已实现的状态之间流动。
模式总结
优点
状态模式将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
所有状态相关的代码都存在于某个ConcereteState中,所以通过定义新的子类很容易地增加新的状态和转换。
状态模式通过把各种状态转移逻辑分不到State的子类之间,来减少相互间的依赖。
缺点
导致较多的ConcreteState子类
适用场景
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式来。
一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态。