参考文献:
[1]Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides.Dedign Patterns Elements of Reusable Object-Oriented Software 北京:机械工业出版社,2010.07;
[2]程杰.大话设计模式 北京:清华大学出版社,2007.10;
目录:
1、策略模式(Strategy):
2、观察者模式(Observable):
1、策略模式(Strategy):
(1)策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与所使用算法类之间的耦合。
(2)结构图:
图1.1 策略模式结构图
①Context:上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用,可定义一个接口来让Strategy访问它的数据。
②Strategy:策略类,定义所有的支持的算法的公共接口。Context使用这个接口来调用某个ConcreteStrategy定义的算法。
③ConcreteStrategyA、ConcreteStrategyB、ConcreteStrategyC:具体策略类,封装了具体的算法或行为,继承于Strategy。
(3)适用范围:
①许多相关的类仅仅是行为不同。
②需要使用一个算法的不同变体。
③算法使用客户不应该知道的数据。
④一个类定义了多种行为,并且这个类的行为在这个类的操作中以多个条件语句的形式出现。
(4)优点:
①有一系列可供重用的算法或行为。
②替代继承,将算法封装在独立的Strategy类中,易理解,易扩展。
③在使用这些行为的类中消除了条件语句。
(5)缺点:
①客户必须了解不同的Strategy。
②Strategy和Context之间的通信开销。
③增加了对象的数目。
(6)示例代码:
实例说明:在使用图像处理软件处理图片后,需要选择一种格式进行保存,然而各种格式在底层实现的算法并不相同,因此使用策略模式与简单工厂模式组合进行实例开发。
图1.2 工程结构
①UserAction.java
package com.remoa.strategy.action;
import java.util.Scanner;
import com.remoa.strategy.factory.TypeChooser;
public class UserAction {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入要保存的图片格式:");
String str = scan.next();
new TypeChooser().outputResult(str);
scan.close();
}
}
②TypeChooser.action
package com.remoa.strategy.factory;
import com.remoa.strategy.strategy.GIFSaver;
import com.remoa.strategy.strategy.ImageSaver;
import com.remoa.strategy.strategy.JPEGSaver;
import com.remoa.strategy.strategy.PNGSaver;
public class TypeChooser {
ImageSaver imageSaver = null;
public void outputResult(String typeStr){
typeStr = typeStr.toLowerCase();
switch(typeStr){
case "png":
imageSaver = new PNGSaver();
break;
case "gif":
imageSaver = new GIFSaver();
break;
case "jpeg":
imageSaver = new JPEGSaver();
break;
}
imageSaver.save();
}
}
③ImageSaver.java
package com.remoa.strategy.strategy;
public interface ImageSaver {
public void save();
}
④GIFSaver.java
package com.remoa.strategy.strategy;
public class GIFSaver implements ImageSaver{
@Override
public void save() {
System.out.println("将图片保存成GIF格式");
}
}
⑤JPEGSaver.java
package com.remoa.strategy.strategy;
public class JPEGSaver implements ImageSaver{
@Override
public void save() {
System.out.println("将图片保存成jpeg格式");
}
}
⑥PNGSaver.java
package com.remoa.strategy.strategy;
public class PNGSaver implements ImageSaver{
@Override
public void save() {
System.out.println("将图片保存成png格式");
}
}
⑦运行结果:
2、观察者模式(Observable):
(1)观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
(2)结构图:
图2.1 观察者模式结构图
①Subject:把所有观察者对象的引用保存在一个聚集里,每个主题可以有任意数量的观察者。抽象主题提供一个观察者,可以增加和删除观察者对象。
②Observer:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
③ConcreteSubject:具体主题类,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
④ConcreteObserver:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
(3)适用范围:
①当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
②当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变。
③当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,不希望这些对象是紧密耦合的。
(4)优点;
①目标和观察者间的抽象耦合。
②支持广播通信。
(5)缺点:
①可能导致意外的更新。在目标上一个看似无害的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。
(6)示例程序:
用观察者模式实现一个汽车驾驶室仪表系统,当汽车改变速度、改变方向时实时显示汽车的速度、方向、指示灯等信息。
如本示例程序,转向灯对象、车速对象、车灯对象互相并不知道对方的存在,这样使得我们可以根据需要单独复用转向灯、车速或车灯。这一行为意味着转向灯、车速或车灯都依赖于数据对象,因此数据对象的任何状态改变都应该通知它们。同时也没有理由将依赖于该数据对象的数目限定为3个,对相同的数据可以有任意数目的不同的依赖于该数据的对象,比如车辆状态改变还可以通知手机的即时显示车辆状态的APP等等。
图2.2 工程结构图
①CarObservable.java
package com.remoa.observablePattern.observable;
import java.util.Observable;
public class CarObservable extends Observable{
private int status = 0;//status为1时为速度改变,为2时为方向改变,为3时为车灯改变。
private double speed = 0;
private String light = "none";
private String direction = "straight";
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
if(this.speed != speed){
this.speed = speed;
this.status = 1;
setChanged();
notifyObservers();
}
}
public String getLight() {
return light;
}
public void setLight(String light) {
if(!light.equals(this.light)){
this.light = light;
this.status = 3;
setChanged();
notifyObservers();
}
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
if(!direction.equals(this.direction)){
this.direction = direction;
this.status = 2;
setChanged();
notifyObservers();
}
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
②DirectionObserver.java
package com.remoa.observablePattern.observer;
import java.util.Observable;
import java.util.Observer;
import com.remoa.observablePattern.observable.CarObservable;
public class DirectionObserver implements Observer{
@Override
public void update(Observable o, Object arg) {
CarObservable carObservable = (CarObservable)o;
String str = carObservable.getDirection();
System.out.println("我是方向观察者,车辆状态有变化,我被告知了");
if(carObservable.getStatus() == 2){
System.out.println("Direction turns " + str + ".");
}
}
}
③PilotLightObserver.javapackage com.remoa.observablePattern.observer;
import java.util.Observable;
import java.util.Observer;
import com.remoa.observablePattern.observable.CarObservable;
public class PilotLightObserver implements Observer{
@Override
public void update(Observable o, Object arg) {
CarObservable carObservable = (CarObservable)o;
String str = carObservable.getLight();
System.out.println("我是车灯观察者,车辆状态有变化,我被告知了");
if(carObservable.getStatus() == 3){
System.out.println("Light in " + str + " opens.");
}
}
}
④SpeedObserver.java
package com.remoa.observablePattern.observer;
import java.util.Observable;
import java.util.Observer;
import com.remoa.observablePattern.observable.CarObservable;
public class SpeedObserver implements Observer{
@Override
public void update(Observable o, Object arg) {
CarObservable carObservable = (CarObservable)o;
double speed = carObservable.getSpeed();
System.out.println("我是速度观察者,车辆状态有变化,我被告知了");
if(carObservable.getStatus() == 1){
System.out.println("The real-time speed is " + speed + "km/s.");
}
}
}
⑤Test.java
package com.remoa.observablePattern;
import com.remoa.observablePattern.observable.CarObservable;
import com.remoa.observablePattern.observer.DirectionObserver;
import com.remoa.observablePattern.observer.PilotLightObserver;
import com.remoa.observablePattern.observer.SpeedObserver;
public class Test {
public static void main(String[] args) {
CarObservable carObservable = new CarObservable();
carObservable.addObserver(new DirectionObserver());
//添加两个转向灯观察者
PilotLightObserver pilotLightObserver1 = new PilotLightObserver();
PilotLightObserver pilotLightObserver2 = new PilotLightObserver();
carObservable.addObserver(pilotLightObserver1);
carObservable.addObserver(pilotLightObserver2);
carObservable.addObserver(new SpeedObserver());
//输出观察者数量
System.out.println("The count of observers are:" + carObservable.countObservers());
carObservable.deleteObserver(pilotLightObserver1);
//输出删除了一个转向灯观察者后的观察者数量
System.out.println("The count of observers are:" + carObservable.countObservers());
//车速提到88.5km/h
System.out.println("----------------车速提到88.5km/h");
carObservable.setSpeed(88.5);
//右转向灯打开
System.out.println("----------------右转向灯打开");
carObservable.setLight("right");
//方向改为向左
System.out.println("----------------方向改为向左");
carObservable.setDirection("left");
//右转向灯打开
System.out.println("----------------右转向灯打开");
carObservable.setLight("right");//右转车灯本来就打开了,此时应该不作处理,故不输出
}
}
⑥运行结果: