HeadFirst设计模式学习笔记

原则

  • 找出应用中需要变化之处,将变化之处独立出来,与不需要变动的部分分开
  • 针对接口编程,而不是针对实现编程
  • 多用组合,少用继承

设计模式

策略模式(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 observers;
        float temperature;
        public MySubject(){
               observers=new ArrayList();
        }
        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是单继承,所以在一定情况下存在限制)。

你可能感兴趣的:(head-first-java,设计模式)