《Head First 设计模式》笔记

文章目录

  • 《Head First 设计模式》笔记
  • 一、策略模式
  • 二、观察者模式
    • 1.问题引入:
      • 1.1气象监测应用概述
    • 2.系统设计:

# 前言 大三党修炼(自动狗头)花点时间了解JAVA中的一些设计模式,写博客是为了帮自己理清思路,希望也能帮到大家来理解设计模式,在学习设计模式前但我知道设计模式对于框架是一种优化,框架并不包含那种设计模式,我也没接触过框架,我希望后面接触框架后能和设计模式进行更多的思考。笔记中会存在疏漏,希望大家多多指出。


一、策略模式

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

1. 问题引入
开发一套成功的模拟鸭子游戏:SimUDuck,游戏中会出现各种各样的鸭子,可以游泳,呱呱叫等多种行为,拥有OO思想。
2.思想的迭代更新
(1)最开始看到问题大家一定会想到直接先定义Duck父类,然后在父类中写方法类来实现鸭子的行为。

abstract class Duck {/*抽象类的使用原则如下:
(1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
(2)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;
(3)抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
(4)子类(如果不是抽象类)则必须重写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。);*/public void quack(){//呱呱叫System.out.println("呱呱呱");}public  void swim(){//游泳System.out.println("游泳");}public abstract void display();//鸭子的外表(因为每一种鸭子的外观都不同,所以该方法是抽象的)要在子类中实现此方法}

如果我现在要引入两种鸭子:红头鸭,绿头鸭。

public class MallarDuck extends Duck{/*绿头鸭重写抽象类的display方法*/@Overridepublic void display() {System.out.println("头顶一片绿");}
}
class RedheadDuck extends  Duck{@Overridepublic void display() {System.out.println("樱木花道鸭");}
}

现在需求来了客户需要鸭子飞起来,那也很简单对不对在Duck中咋加一个fly()方法,创建的子类只要调用就好了。多简单!然而事实不是如此,有些鸭子是不会飞的如橡皮鸭(即某些不适合该行为的子类也具备了该行为),那我重写父类方法不就好了。

class RubberDuck extends Duck{@Overridepublic void display() {System.out.println("橡皮");}@Overridepublic void quack() {System.out.println("吱吱");}@Overridepublic void fly() {System.out.println("我飞不了");}
}

但是如果我加入更多类似的玩具鸭他不会飞也不会叫就得又要开始重写这几个方法。所以继承的思想不适合处理需求多变的情况。

(2)转换思路利用接口如何?

可以把fly()从Duck中取出来放入Flyable接口中,以此类推取出Quack变成接口Quackable等其他变化多的方法。

public interface Flyable {//飞行接口类
/*
1)接口不能有构造方法,抽象类可以有。2)接口不能有方法体,抽象类可以有。3)接口不能有静态方法,抽象类可以有。4)在接口中凡是变量必须是public static final,而在抽象类中没有要求。
*/abstract public void fly();}
public interface Quackable {abstract  public void quack();
}

有了接口后我们通过子类来实现接口类,这时候橡皮鸭,玩具鸭之类的依据自己的需求来选择接口实现,如橡皮鸭不会飞我就不去实现这个接口。

class RubberDuck extends Duck implements Quackable {@Overridepublic void display() {System.out.println("橡皮");}@Overridepublic void quack() {System.out.println("吱吱");}}

但是新的问题又出现了重复的代码又会变多了例如之前的绿头鸭,后头鸭要实现两个接口重写接口中的抽象方法就会使得代码重复增加

public class MallarDuck extends Duck implements Flyable,Quackable{/*绿头鸭重写抽象类的display方法*/@Overridepublic void display() {System.out.println("头顶一片绿");}public void fly(){System.out.println("飞");}@Overridepublic void quack() {System.out.println("嘎嘎噶");}}
class RedheadDuck extends  Duck implements Flyable,Quackable{@Overridepublic void display() {System.out.println("樱木花道鸭");}@Overridepublic void fly() {System.out.println("飞");}@Overridepublic void quack() {System.out.println("嘎嘎");}
}

例如飞行和叫声一样,如果多个类似会飞会叫的就会不断地重复代码。(手动狗头:终于理解了软件工程中前期是多么重要。。。。)

(3)采用良好的OO设计原则
我们现在的代码要解决的是用一种既有的代码影响最小的方式来修改软件,花更少的时间,而更多的让程序去做更cool的事

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

现在我要把飞行和呱呱叫取出变成行为类,如何设计?
设计原则2:针对接口编程,而不是针对实现编程。

所以我们利用接口来代表每个行为,如将飞行类接口有不会飞和会飞两种实现类实现,如下.

public interface FlyBehavior {public void fly();
}

接着我们写会飞和不会飞的实现类

public class FlyNoWay implements FlyBehavior {@Overridepublic void fly() {System.out.println("我不会飞");}
}
public class FlyWithWing implements FlyBehavior {@Overridepublic void fly() {System.out.println("飞飞飞飞");}
}

还有瓜瓜叫的行为和多种叫声实现类

public interface  QuackBehavior {abstract public void quack();
}
public class NutQuack implements QuackBehavior {public void quack() {System.out.println("不会叫");}
}
public class Quack implements QuackBehavior {@Overridepublic void quack() {System.out.println("呱呱呱");}
}
public class Squeak implements QuackBehavior {@Overridepublic void quack() {System.out.println("吱吱吱");}
}

那到这大家也和我有一样的疑问那我们该如何调用实现接口呢?
答案是多态用到的同样是子类型重写父类新但和我们最初的多态在形式上有 点不一样,在于其多态是在Duck的子类对象中调用转型。(个人理解)我们首先来看如何改造Duck父类

public abstract class Duck {//行为接口类型声明俩引用变量,所有鸭子子类(在同一个package中)都继承他们FlyBehavior flyBehavior;QuackBehavior quackBehavior;public Duck(){}public  void swim(){//游泳System.out.println("游泳");}public abstract void display();//鸭子的外表(因为每一种鸭子的外观都不同,所以该方法是抽象的)要在子类中实现此方法//委托给行为类public void performFly(){flyBehavior.fly();}public  void  performQuack(){quackBehavior.quack();}
}

这时我们来写子类中的构造方法,因为绿头鸭使用Quack类处理,所以当Duck的performQuack();呱呱叫的职责被委托给Quack对象,而我们得到了真正地呱呱呱。(这段有点难懂 ,我之前再写构造函数时写的public void MallarDuck导致程序出错说flybehavior为null,出错之后我理解了是那句话会导致程序认为他是方法,没有给所谓的被委托对象赋值。)

public class MallarDuck extends Duck {public  MallarDuck(){//构造方法quackBehavior=new Quack();flyBehavior=new FlyWithWing();}/*绿头鸭重写抽象类的display方法*/@Overridepublic void display() {System.out.println("头顶一片绿");}}

我们再来试着写一下橡皮鸭子类,明确一下橡皮鸭会吱吱叫,但不会飞,则实现方法是FlyNoWay()和Squeak();我们只需要吧quackBehavior,flyBehavior
的赋值即可

class RubberDuck extends Duck {public RubberDuck(){flyBehavior=new FlyNoWay();quackBehavior=new Squeak();}@Overridepublic void display() {System.out.println("橡皮");}}

那我们该如何在主函数调用呢?

public class test {public static void main(String[] args) {Duck mallard=new MallarDuck();mallard.display();mallard.performQuack();mallard.performFly();Duck rubber=new RubberDuck();rubber.display();rubber.performFly();rubber.performQuack();}}

我们现在来看一下这个调用过程那橡皮鸭的行为来说我们首先像多态一样创建对象——橡皮鸭,利用Duck调用(ps:作为小白的我前面说过抽象对象不能实例化,这里很巧妙他用的对象是子类缺用父类调用,涨知识了!!!)
话说回来这时候就会在构造函数中赋对应的方法:
flyBehavior=new FlyNoWay();
quackBehavior=new Squeak();
主函数中rubber.performFly()进入父类Duck中的performFly()方法里的flyBehavior.fly();而flyBehavior是飞行行为接口类对象的变量类型,fly()就是调用接口方法,这里用到了多态就会去吱吱叫和不会飞的实现方法类。
结果如下:

吼吼吼这样我们的方法完美解决了过多的重写重复的代码(第一个设计方法我前前后后看了三遍才看懂泪目。。。)
在子类中的构造方法我们可以改成设定方法放在Duck中

public void setFlyBehavior(FlyBehavior fb){flyBehavior=fb;
}

主函数就可以写成

 Duck mallard=new MallarDuck();mallard.setsetFlyBehavior(new FlyWithWing());

2.总结
1.在该中客户使用封装好的飞行和呱呱叫的算法族,其中每个行为看作一个算法族。
2.鸭子行为不是继承而来而是和适当的对象组合而来。
3.组合建立的系统具有强大的弹性,不仅可以将算法族封装成类,更可以“在运行时动态的改变行为”。

二、观察者模式

1.问题引入:

需要开发气象站系统,WeatherDate对象负责追踪目前的天气状况,要求系统有三种布告板来分别显示天气状况,气象统计和预报。布告板信息实时更新,还有一个程序接口来让其他人员实现自己的布告板。

1.1气象监测应用概述

系统整体上是由:气象站检测设备,WeatherDated对象(追踪气象向状况和更新布告板)和布告板组成;

2.系统设计:

错误设计:

public class WeatherDate {public float  getTempareture(){float tempareture=22;return tempareture;}public float  getHumidity(){float gethumidity=6;return  gethumidity;}public float  getPressure(){float getpressure=2231;return getpressure;}public void measurementsChanged(){float temp=getTempareture();float humidity=getHumidity();float pressure=getPressure();currentConditionsDisplay.Update(temp,humidity,pressure);//调用布告器更新方法;//同理更新湿度,压强;}
}

由于这里的currentConditionsDisplay.Update明显是针对具体实现编程,这样做会使以后的对布告器修改时,必须修改程序。因此我们考虑如下方法:

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

可以用Subject与Observer接口的类设计的做法实现:
1.定义Subjecct接口,Observer接口,DisplayElement接口(显示最新信息)
接口与接口实现依赖;

《Head First 设计模式》笔记相关推荐

  1. 《信贷的逻辑与常识》笔记

    序 银行信贷风险管理的反思 现状与趋势 银行贷款的质量变化与经济周期.宏观调控政策等存在很高的相关性 现在银行不良贷款的增加主要是前几年经济快速增长时企业过度投资.银行过度放贷所带来的结果. 从历史情 ...

  2. AI公开课:19.02.27周逵(投资人)《AI时代的投资逻辑》课堂笔记以及个人感悟

    AI公开课:19.02.27周逵(投资人)<AI时代的投资逻辑>课堂笔记以及个人感悟 目录 课堂PPT图片 精彩语录 个人感悟 课堂PPT图片 精彩语录 更新中-- 文件图片已经丢失-- ...

  3. 人工智能入门算法逻辑回归学习笔记

    逻辑回归是一个非常经典的算法,其中也包含了非常多的细节,曾看到一句话:如果面试官问你熟悉哪个机器学习模型,可以说 SVM,但千万别说 LR,因为细节真的太多了. 秉持着精益求精的工匠精神不断对笔记进行 ...

  4. 【逻辑回归学习笔记】

    算法描述 1.逻辑回归要做的事就是寻找分界面实现二分类. 2.问题假设:对一堆三角形和正方形分类. 3.数据输入:已知正方形和三角形的坐标和标签. 4.算法过程: 知识储备 1.分类和回归 ①分类的目 ...

  5. 逻辑回归函数学习笔记

    继续逻辑回归学习,今日笔记记录. 1.逻辑回归和线性回归的关系:对逻辑回归的概率比取自然对数,则得到的是一个线性函数,推导过程如下. 首先,看逻辑回归的定义 其次,计算两个极端y/(1-y),其值为( ...

  6. 2.2 逻辑回归-机器学习笔记-斯坦福吴恩达教授

    逻辑回归 上一节我们知道,使用线性回归来处理 0/1 分类问题总是困难重重的,因此,人们定义了逻辑回归来完成 0/1 分类问题,逻辑一词也代表了是(1) 和 非(0). Sigmoid预测函数 在逻辑 ...

  7. LVM逻辑卷分区笔记

    磁盘的静态分区有其缺点:分区大小难评估,估计不准确,当分区空间不够用的时候,系统管理员可能需要先备份整个系统,清除磁盘空间,然后重新对磁盘进行分区,然后恢复磁盘数据到新分区,且需要停机一段时间进行恢复 ...

  8. 适合理工直男的钟平老师逻辑英语学习笔记

    一切的一切都只是套路!             --鲁迅 核心公式: En: (状语1) 主(定语1) 谓(状语2) (宾)(定语2) (状语1) Ch: (状语1) (定语1)主 (状语2)谓 (定 ...

  9. 【数字逻辑】学习笔记 第四章 Part2 常用组合逻辑电路与竞争、险象

    文章目录 一.常用组合逻辑电路 1. 译码器 (1) 二进制译码器 74LS138(3/8译码器) a. 一般符号和图形符号 b. 74LS138功能表 c. 两片 `74LS138` 构成 `4-1 ...

  10. 线性回归、逻辑回归学习笔记

    学习源代码 import numpy as np import matplotlib.pyplot as plt def true_fun(X): # 这是我们设定的真实函数,即ground trut ...

最新文章

  1. 程序员的自我修养--链接、装载与库笔记:系统调用与API
  2. SSM整合(2): spring 与 mybatis 整合
  3. JS转字符 判断数字等
  4. 监听器第一篇【基本概念、Servlet各个监听器】
  5. MyEclipse创建Maven工程
  6. 通过PMP认证考试的心得分享
  7. 神经网络控制与matlab仿真,神经网络模型matlab例子
  8. vue 在线预览word、excel、pdf、txt、图片
  9. (1)pytorch 实现 minist手写数据集(cpu/gpu)版本
  10. html5游戏开发教程实战:五子棋、四子棋、围棋、翻转棋四种对弈游戏,仅仅100行代码
  11. oracle三大连接方式,oracle的三种连接方式
  12. 16s扩增子 qiime2 实战
  13. STM32之俄罗斯方块
  14. python生成简单二维码_使用Python生成个性二维码
  15. 微信小程序获取微信卡包发票原件及格式化发票信息
  16. Windows Server 2008密码破解
  17. 力扣739:每日温度【C++】
  18. 常见计算机主机内部硬件设备,电脑主机内部有哪些配件,电脑硬件组成图解
  19. 物联网下的智能家居 生活智能化不再遥远
  20. 使用MaxCompute搭建社交好友推荐系统

热门文章

  1. 网络协议——七层、五层、四层协议概念
  2. 【基础知识】SPI通信协议
  3. idea如何选择性合并其他分支的代码
  4. Word中用Endnote插入的引用如何快速定位到参考文献
  5. 服务器查询IPV6地址
  6. 推荐:电脑蓝屏代码分析工具BlueScreenView简体中文版下载
  7. 概率论——随机变量及其分布
  8. sed命令详解与示例
  9. 薛兆丰经济学思维研究:权利在真实生活中的硬度
  10. 加油(c++程序猿)