原则
- 找出应用中需要变化之处,将变化之处独立出来,与不需要变动的部分分开
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
设计模式
策略模式(strategy pattern)
-
实例
-
首先,定义抽象类和接口
public abstract class Duck {
private FlyBehavior flyBehavior;
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void display(){
System.out.println("hey , i am a duck!");
}
}
---------------------------------------------------------
public interface FlyBehavior {
void fly();
}
然后定义具体的类并实现接口
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("oh, i cannot fly!");
}
}
public class FlyRocketPower implements FlyBehavior {
@Override
public void fly() {
System.out.println("i can fly ~~~~");
}
}
public class ModelDuck extends Duck {
public ModelDuck() {
this.setFlyBehavior(new FlyNoWay());
}
}
使用
public class Main {
public static void main(String[] args) {
System.out.println("-------- God made a model duck with mud --------");
Duck duck = new ModelDuck();
duck.display();
duck.performFly();
System.out.println("-------- God gives the model duck the ability to fly --------");
duck.setFlyBehavior(new FlyRocketPower());
duck.performFly();
}
}
分析
对于鸭子来说,飞行能力是一种变动的能力,有些鸭子能飞,而有些鸭子不能。如果直接在Duck这个抽象类中就定义了鸭子的飞行能力,显然并不合适;如果将飞行能力抽象为一个接口,让每个能飞行的鸭子都继承这个接口的话,会存在一个问题,即:每个会飞行的鸭子都需要实现这个接口的飞行方法,从而使飞行这个功能存在代码重复。因此,在策略模式中,采用这样一种方法,即:将飞行能力抽象为一个接口,但是该接口是以组合的形式作为Duck的一个字段,并在Duck内部提供performFly方法来调用接口。这样做的好处是:可以根据情况,将不同的飞行行为注入到不同的Duck子类中(复用飞行行为的实现代码),甚至可以在程序运行的时候,动态替换其飞行行为。
观察者模式
-
实例
-
定义接口
public interface Subject{
public void registerObserver(Observer o);
public void deleteObserver(Observer o);
public void notifyAllObservers();
}
public interface Observer{
public void update(float temperature);
}
接口实现
public class MySubject implements Subject{
ArrayList<Observer> observers;
float temperature;
public MySubject(){
observers=new ArrayList<Observers>();
}
public void registerObserver(Observer o){
observers.add(o);
}
public void deleteObserver(Observer o){
int index=observers.indexof(o);
if(index>=0)observers.remove(index);
}
public void notifyAllObservers(){
for(Observer o:observers)o.update(temperature,humidity,pressure);
}
public void setMeasurements(float temperature){
this.temperature=temperature;
notifyAllObservers();
}
}
public class MyObserver implements Observer{
Subject subject;
public MyObserver(Subject s){
this.subject=s;
s.registerObserver(this);
}
public void update(float temperature){
System.out.println("得到来自subject的消息");
}
}
使用
MySubject ms=new MySubject();
Observer o=new MyObserver(ms);
//一旦调用该方法来更新MySubject中的数据,则所有注册过的Observer都会得到通知
ms.setMeasurements(temperature);
分析
两种角色:subject 和 observer。observer订阅subject,subject中的数据有变化时,能推送到各个已经订阅的observer上去。并且,这两种角色都是以接口的形式定义。
关键在于:subject中维护着一张所有已订阅该subject的observer列表;observer中含有指向subject的引用。
在java种,也存在observable抽象类和observer接口,分别对应观察者模式中的subject接口和observer接口。并且,在observable中,每次调用notifyObservers()方法之前,都需要调用setChange()方法,用来将标明状态改变的标志位设为true。notifyObservers()方法在内部会判断标志位是否为true,只有在位true的情况下才会真正的通知观察者(由于observable是一个抽象类,而java是单继承,所以在一定情况下存在限制)。