• 【笔记】Head First 设计模式


    设计原则
    找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

    设计原则
    针对接口编程,而不是针对实现编程。

    问:用一个类代表一个行为,感觉似乎有点奇怪。
    类不是应该代表某种“东西”吗?类不是应该同时具备
    状态“与”行为吗?
    答:在OO系统中,是的,类代表的东西一般都
    是既有状态(实例变量)又有方法。只是在本例中,碰
    巧“东西”是个行为。但是即使是行为,也仍然可以有
    状态和方法,例如,飞行的行为可以具有实例变量,记
    录飞行行为的属性(每秒翅膀拍动几下、最大高度和速
    度等)。

    问:Duck是不是也该设计成一个接口?
    答:在本例中,这么做并不恰当。如你所见的,
    我们已经让一切都整合妥当,而且让Duck成为一个具
    体类,这样可以让衍生的特定类(例如绿头鸭)具有
    Duck共同的属性和方法。我们已经 从Duck的继承结构中
    删除了变化的部分,原先的问题都已经解决了,所以不
    需要把Duck设计成接口。

    测试Duck的代码
    1,输入并编译下面的Duck类(Duck.java)以及两页前的
    MallardDuck类(MallardDuck.java)。

    public abstract class Duck {
       FlyBehavior flyBehavior;//为行为接口类型声明两个引
       QuackBehavior quackBehavior;//用变量,所有鸭子子类(在同一个zackage中)都继承它们
       public Duck() {
       } 
       
       public abstract void display();
       public void performFly() {
          flyBehavior.fly();//委托给行为类
       }
       public void performQuack() {
          quackBehavior.quack();//委托给行为类
       } 
       public void swim() {
          System.out.println(“All ducks float, even decoys!”);
       }
    }

    2,输入并编译FlyBehavior接口(FlyBehavior.java)与两个行为实现

    类(FlyWithWings.java与FlyNoWay.java)。

    public interface FlyBehavior {
       public void fly();//所有飞行行为类必须实现的接口。
    }
    public class FlyWithWings implements FlyBehavior {   
       public void fly() {
      System.out.println(“I’m flying!!”);//这是飞行行为的实现,给“真会”飞的鸭子用……
       }
    }
    public class FlyNoWay implements FlyBehavior {
       public void fly() {
           System.out.println(“I can’t fly”);//这 是 飞 行 行 为 的 实 现 ,给“不会”飞的鸭子用(包括橡皮鸭和诱饵鸭)。
       }
    }

    3.输入并编译QuackBehavior接口(QuackBehavior.java)及其三个实现类

    (Quack.java、MuteQuack.java、Squeak.java)。

    public interface QuackBehavior {
       public void quack();
    }
    public class Quack implements QuackBehavior {
       public void quack() {
          System.out.println(“Quack”);
       }
    }
    public class MuteQuack implements QuackBehavior {
       public void quack() {
      System.out.println(“<< Silence >>”);
       }
    }
    public class Squeak implements QuackBehavior {
       public void quack() {
      System.out.println(“Squeak”);
       }
    }

    4,输入并编译测试类(MiniDuckSimulator.java)

    public class MiniDuckSimulator {
       public static void main(String[] args) {
          Duck mallard = new MallardDuck();
          mallard.performQuack();//这会调用MallardDuck继承来的performQuack() 方法,进而委托给该对象的QuackBehavior对象处理(也就是说,调用继承来的quackBehavior引用对象的quack())。
          mallard.performFly();
       }
    }

     动态设定行为

    在鸭子里建立了一堆动态的功能没有用到,就太可惜了!假设我们想在鸭子子类中通
    过“设定方法(setter method)”来设定鸭子的行为,而不是在鸭子的构造器内实例化。

    1,在Duck类中,加入两个新方法:

    public void setFlyBehavior(FlyBehavior fb) {
        flyBehavior = fb;
    }
    public void setQuackBehavior(QuackBehavior qb) {
        quackBehavior = qb;
    }

    2,制造一个新的鸭子类型:模型鸭(ModelDuck.java)

    public class ModelDuck extends Duck {   
        public ModelDuck() {
           flyBehavior = new FlyNoWay();//一开始,我们的模型鸭是不会飞的。
      quackBehavior = new Quack();
        }
        public void display() {
           System.out.println(“I’m a model duck”);
        }
    }

    3,建立一个新的FlyBehavior 类型(FlyRocketPowered.java)

    public class FlyRocketPowered implements FlyBehavior {
        public void fly() {
           System.out.println(“I’m flying with a rocket!”);
           //没关系,我们建立一个利用火箭动力的飞行行为。
        }
    }

    4,改变测试类(MiniDuckSimulator.java),加上模型鸭,并使模型鸭具有火箭动力。

    public class MiniDuckSimulator {
       public static void main(String[] args) {
          Duck mallard = new MallardDuck();
          mallard.performQuack();
          mallard.performFly();
       
              Duck model = new ModelDuck();
              model.performFly();//第一次调用performFly() 会被委托给flyBehavior对象(也就是FlyNoWay实例),该对象是在模型鸭构造器中设置的。
              model.setFlyBehavior(new FlyRocketPowered());//这会调用继承来的setter方法,把火箭动力飞行的行为设定到模型鸭中。哇!模型鸭突然具有了火箭动力飞行能力!
              model.performFly();  //如果成功了,就意味着模型鸭可以动态地改变它的飞行行为。如果把行为的实现绑死在鸭子类中,可就无法做到这样了。
       }
    }

     二,观察者(Observer)模式

    先看一个错误示范
    这是第一个可能的实现:我们依照Weather-O-Rama气象站开发人员的暗示,在
    measurementsChanged()方法中添加我们的代码:

    public class WeatherData {
        // 实例变量声明
        public void measurementsChanged() {
            //调用 WeatherData  的三个getXxx()方法,以取得最近的测量值。这些getXxx()方法已经实现好了。
            float temp = getTemperature();
            float humidity = getHumidity();
            float pressure = getPressure();
            //现在,更新布告板……
            currentConditionsDisplay.update(temp, humidity, pressure);
            statisticsDisplay.update(temp, humidity, pressure);
            forecastDisplay.update(temp, humidity, pressure);
            //不对的地方:
            //1.针对具体实现编程,会导致我们以后在增加或删除布告板时必须修改程序。
            //2.至少,这里看起来像是一个统一的接口,布告板的方法名称都是update(),参数都是温度、湿度、气压。
        }
        // 这里是其他WeatherData方法
    }

    认识观察者模式
    我们看看报纸和杂志的订阅是怎么回事:
    1.报社的业务就是出版报纸。
    2.向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。
    3.当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。
    4.只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸。

    出版者+订阅者=观察者模式

    如果你了解报纸的订阅是怎么回事,其实就知道观察者模式是怎么回事,只是名称不太一样:

    出版者改称为“主题”(Subject),订阅者改称为“观察者”(Observer)。

    观察者模式的一天

  • 相关阅读:
    Topshelf的使用
    ref和out的区别
    .NET编码解码(HtmlEncode与HtmlDecode)
    查询表中某字段有重复记录个数的方法
    ActiveReports 报表应用教程 (8)---交互式报表之动态过滤
    ActiveReports 报表应用教程 (7)---交叉报表及数据透视图实现方案
    ActiveReports 报表应用教程 (6)---分组报表
    ActiveReports 报表应用教程 (5)---解密电子商务领域首张电子发票的诞生(套打报表)
    ActiveReports 报表应用教程 (4)---分栏报表
    ActiveReports 9 新功能:借助目录(TOC)控件为报表添加目录功能
  • 原文地址:https://www.cnblogs.com/FH-cnblogs/p/4306747.html
Copyright © 2020-2023  润新知