Java设计模式研究

来源:互联网 发布:mac废纸篓清空还原 编辑:程序博客网 时间:2024/06/08 07:20

库与框架无法帮助我们将应用组织成容易了解、容易维护、具有弹性的架构,所以需要设计模式。

模式不是发明,而是发现。模式不是代码,而是方案。

以下模式被认为是历经验证的OO设计经验。


1. 观察者模式

1) 类图



2) 定义

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它所有依赖者都会收到通知并自动更新


3)设计原则 

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


4)实现原理

Subject主题类是事件的主导者,通过registerObserver()注册上有需求的观察者,

通过NotifyObserver()实时更新自己状态并告知已经注册的各位观察者。

observer.update(); 由每位观察者自行处理更新的数据。

观察者构造函数里指定主题,并调用该主题的registerObserver()方法实现绑定。

public class WeatherData implements Subject {private ArrayList observers;public WeatherData() {observers = new ArrayList();}public void registerObserver(Observer o) {observers.add(0);}public void removeObserver(Observer o) {int i = observers.indexOf(o);if (i >= 0) {observers.remove(i);}}public void notifyObserver() {for (int i = 0; i < observers.size(); i++) {Observer observer = (Observer)observers.get(i);observer.update(temperature, humidity, pressure);}}}
public class CurrentCondition {private Subject weatherData;public CurrentCondition (Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}public void update(float t, float h, float p) {display(t, h, p);}}

5)点评

如果让观察者去“拉”主题的数据,这样主题会门户大开,被大肆挖掘数据,不够安全。

所以更常用的设计是主题主动“推”送数据给观察者,主题不关心观察者的具体情况,实现松耦合。


6)应用场景

一对多的关系,多个对象实时监听一个对象的状态。

系统级更常见,比如建立一个对象,监听按键,传感器数据等。



2. 策略模式

1) 类图


2) 定义

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


3)设计原则 

针对接口编程,而不是针对实现编程。多用组合,少用继承。

把系统中会变化的部分抽离出来封装


4)实现原理

在这个类中加一个接口,把行为委托给这个接口处理,

在这个接口下有各种不同的策略实现它的行为,

客户只要通过set和get动态地设置变量就可以在运行时引用正确的策略。

public abstract class Duck {FlyBehavior flyBehavior;public Duck () {}public void setFlyBehavior(FlyBehavior fb) {flyBehavior = fb;}public FlyBehavior getFlyBehavior() {return flyBehavior;} public void performFly () {flyBehavior.fly(); }}public class FlyWithWings implements FlyBehavior {public void fly() {... ...}}


5)点评

策略模式使用委托模型,增加了对象数量,使代码较复杂,但使用对象组合,所以更具有弹性。


6)应用场景

适用于需要经常更换策略的场景。
典型的一个例子:游戏人物换装备,一类装备只能选一种。


3. 状态模式

1) 类图

基本同策略模式,唯一区别在于委托的状态是一个抽象类而不是接口。


2) 定义

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


3)点评

将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个,

状态是用在Context中来代表它的内部状态以及行为的,客户不会直接改变context的状态,改变状态是方案中事先定义好的。


4)应用场景

适用于同一行为在不同条件下产生不同表现的场景,把条件看成状态,或者策略。


4. 装饰者模式

1) 类图


2) 定义

动态地将责任附加到对象身上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。


3)设计原则 

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


4)实现原理

新功能以装饰者的身份呈现,让装饰者继承被装饰者,
装饰者构造函数里把被装饰者当做参数传入,再由构造器将其记录在实例变量中。
public class Mocha extends CondimentDecorator {Beverage beverage;public Mocha(Beverage beverage) {this.beverage = beverage;}public double cost(){return .20 + beverage.cost();}}

5)点评

装饰者与被装饰者必须是同一类型,用继承达到类型匹配。

装饰者模式的设计中加入了大量的小类,会让程序变得复杂难懂。


6)应用场景

对象须要添加一个新功能,新功能具有弹性,易于修改更新替代或叠加,同时不会改变原有对象。

典型例子比如JAVA I/O里的读写功能。



5. 适配器模式

1) 类图



2) 定义

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

3)实现原理

客户通过目标接口调用适配器的方法对适配器发出请求。

适配器把请求转换成被适配者的接口。

客户接收到调用的结果,但并未察觉适配器在中间的作用。

public class EnumerationIterator implements Iterator{Enumeration enum;public EnumerationIterator(Enumeration enum) {this.enum = enum;}public boolean hasNext() {return enum.hasMoreElements();}public Object next() {return enum.nextElement();}public void remove() {throw new UnsupportedOperationException();}}


4)点评

如果不用适配器,客户就必须改写代码来调用新的接口。

适配器允许客户使用新的库和子集合而无须改变代码,由适配器负责转换。


5)应用场景

有新的客户需求,不想改变客户代码,又想保留原有系统接口,那么考虑用适配器模式作中间层转换。



6. 外观模式

1) 类图



2)定义

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


3)设计原则

最少知识”原则:只和你的密友谈话。

就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件

4) 点评
外观模式没有封装于系统的类,外观只提供简单的接口,依然将系统完整的功能暴露出来。
外观不只简化了接口,也将客户从组件的子系统中解耦。

5)应用场景

某对象具备复杂的功能,客户希望使用简单的高层接口。

典型的例子如家庭影院系统。



7. 工厂方法模式

1) 类图



2) 定义

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


3)设计原则

依赖倒置原则:要依赖抽象,不要依赖具体类。

不能让高层组件依赖低层组件,而且两者都应该依赖于抽象。

遵循倒置原则应注意:

  • 变量不可以持有具体类的引用
  • 不要让类派生自具体类
  • 不要覆盖基类中已实现的方法

4)实现原理

首先声明一个工厂方法factroyMethod(),工厂方法将客户和实际创建具体产品的代码分隔开来。

子类工厂继承抽象工厂,子类工厂的工厂方法具体实现低层组件-产品。

public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza;pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box;return pizza;}abstract Pizza createPizza(String type);}public class NYPizzaStore extends PizzaStore {Pizza createPizza(String item) {if (item.equals("cheese")) {return new NYStyleCheesePizza();} else if (item.equals("veggie")) {return new NYStyleVeggiePizza();} else if (item.equals("clam")) {return new NYStyleClamPizza();} else if (item.equals("pepperoni")) {return new NYStylePepperoniPizza();} else return null;}}
客户只要实例化具体的子类工厂,让子类工厂生产产品。

public static void main () {PizzaStore nyStore = new NYPizzaStore();Pizza pizza = nyStore.orderPizza("cheese");}


5)点评

工厂方法让子类决定要实例化的类是哪一个,选择使用哪个子类就决定了实际创建哪个产品。

将创建对象的代码集中在一个对象或方法中,可以避免代码的重复,且方便维护。

客户在实例化对象时,只会依赖于接口,而不是具体类。

除了工厂方法模式,还有抽象工厂模式,有利于创建对象的家族。



8. 单件模式

1) 定义

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


2)实现原理

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


3)应用场景

独一无二的资源,比如线程池,缓存,对话框,偏好,日志,设备驱动等。

这些对象可能非常耗资源,而且初始化后程序一直没有使用它。



9. 命令模式

1) 类图



2) 定义

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

3)实现原理

关键要理清客户,发起者Invoker,接收者Receiver三者的关系以及命令对象Command与具体动作receiver.Action()之间的关系。

  • 客户提出请求 - 客户创建一个具体命令对象,这个命令对象暴露execute()接口
  • 发起者封装请求 - 发起者由setCommand()持有用户提出的具体命令,并在某个时刻调用命令对象的execute(),实施动作
  • 接收者实现请求 - 具体命令对象定义了动作receiver.Action()和接收者之间的绑定关系

调用者只要调用execute()就可以发出请求,由具体命令调用接收者的一个或多个动作。

public interface Command {public void execute();}public class LightOnCommand implements Command { //具体命令Light light;public LightOnCommand(Light light) {this.light = light;}public void execute() {light.on();  // 具体动作}}public class SimpleRemoteControl {  //调用者Command slot;public SimpleRemoteControl () {}public void setCommand(Command command) {  //调用者持有用户的具体命令slot = command;}public void buttonWasPressed() {  //实施动作的时刻slot.execute();}}public class RemoteControlTest {public static void main() {SimpleRemoteControl remote = new SimpleRemoteControl();  Light light = new Light();LightOnCommand lightOn = new LightOnCommand(light);  //用户创建具体命令remote.setCommand(lightOn);remote.buttonWasPressed();}}

4)点评

一旦有新的动作加入,发起者并不需要改变。


5)应用场景

典型例子:多功能on/off按钮,记录状态可撤销动作,使用宏命令的party模式

更多应用:队列请求,日志请求


10. 模板方法模式

1) 类图



2) 定义

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


3)设计原则

好莱坞原则:别调用我们,我们会调用你。


4)点评

当子类必须提供算法中的某个方法或步骤的实现时,就使用抽象方法。

如果算法的这个部分是可选的,就用钩子,要不要挂钩由子类决定。

模板方法模式是最常用的模式。


原创粉丝点击