您的位置:首页 > 编程语言 > Java开发

《Head First 设计模式》学习心得笔记

2018-01-13 12:59 435 查看

一. 策略模式

用接口和实现的方法,代替OO的具体实现,让不同实现之间可以互相替换。

二. 观察者模式

主题(可理解为服务器)与观察者(可理解为客户端),只要依旧遵守两者之间的接口,那么改变两者中任意一个,都不会影响另一方(松耦合)。

观察者模式的一个主题对象改变状态时,它的所有依赖者都会收到通知,并自动更新。

关于java 自带 Observable:

有多个观察者时,不可以依赖特定的通知次序。

Java自带 Observable 缺陷:Observable 是一个类,并不是接口,只能用继承方法创建一个派生类,而 Java 不支持多重继承,故限制了 Observable 的复用能力。

三. 装饰者模式

装饰者与被装饰者必须是同样的类型(即具有同样的抽象基类)。

装饰者与被装饰者继承于同样的抽象基类,是为了有正确的类型,而不是继承抽象基类的行为。相对而言,行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。

Java.IO 包即为装饰者模式的应用之一。

(重要原则):对扩展开放,对修改关闭

四. 工厂模式

工厂方法模式:让子类决定该创建的对象是什么,达到将对象创建的过程进行封装的目的。工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个(决定的意思是指:在编写创造者类时,不需要知道实际创建的产品是哪一个)。

工厂方法模式的优点之一:帮助我们将产品的“实现”从“使用”中解耦。

(重要原则)依赖倒置原则:要依赖抽象,不要依赖具体类。

避免在 OO 设计中违反依赖倒置原则的几条原则(原则之间存在一定矛盾,并非随时都需要遵循该原则):

变量不可以持有具体类的引用(使用 new,就会持有具体类的引用);

不要让类派生自具体类(否则会依赖具体类),应该派生自一个抽象(接口或者抽象类);

不要覆盖基类中已经实现的方法(基类中已经实现的方法,应该由所有子类共享);

抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。换句话说:抽象工厂允许用户使用接口创建一组相关的产品,但不需要关注实际产出的产品具体是什么。这样,用户与产品的生产过程没有关系,即两者解耦。

抽象工厂的方法,经常以工厂方法的方式实现。

五. 单件模式

单件模式:确保一个类只有一个实例,并提供一个全局访问点。

将构造器声明为私有 private,类内才可以调用构造器,并定义 getInstance() 方法返回该实例对象。

单件模式原则上确保一个类只有一个实例,但仍有可能会出现多实例的情况。针对这种情况,可使用同步方法,令每个线程进入该方法之前,需要等候其他线程离开该方法(不会存在多个线程同时进入该方法)。但另一方面,这种做法可能会令效率较大程度的降低。

P.S:关于 volatile 与 synchronized 关键字:

Java 中,volatile 关键字被用于多线程的并发编程中;

当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存;当有其他线程需要读取时,它会去内存中读取新值;

同时,volatile 关键字禁止进行指令重排序;

volatile 关键字保证变量的可见性,不保证操作的原子性,一定程度上保证指令的有序性;

由于 volatile 无法保证操作的原子性,所以虽然 volatile 的性能由于 synchronized 关键字,但 synchronized 关键字也不能被 volatile 取代。

六. 命令模式

命令模式的 UML 图如下:



客户 (Client):负责创建一个具体命令 (ConcreteCommand) ,并设置其接收者 (Receiver)

调用者 (Invoker):持有一个命令对象,并在某个时间点调用命令对象 (Command) 的 execute() 方法,执行请求;

命令对象 (Command) :为所有命令声明一个接口。调用命令对象的 execute() 方法,即可以令接收者 (Receiver) 执行相关的动作;undo() 方法也可以实现撤销动作;

具体命令对象 (ConcreteCommand)命令对象 (Command) 接口的具体实现,定义了动作和接收者 (Receiver) 之间的绑定关系。调用者 (Invoker)只要调用 execute() 方法就可以发出请求,然后由 具体命令对象 (ConcreteCommand) 调用接收者 (Receiver) 的一个或多个动作;

接收者 (Receiver) :知道如何进行必要的工作,实现这个请求。任何类都可以当接收者 (Receiver)

命令模式部分心得如下:

命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。同时也支持可撤销的操作。

命令模式的作用,在于将发出请求的对象执行请求的对象进行解耦操作

被解耦的两者之间,是通过命令对象 (Command) 进行沟通的。

七. 适配器模式

适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。

客户使用适配器的过程:

首先,客户通过目标接口,调用适配器的方法,对适配器发出请求;

然后,适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口;

最后客户接收到调用的结果;

在该过程中,客户并未察觉到一切操作是适配器在其转换作用,也可以说,客户与被适配者之间是解耦的,互相是不知道对方的存在的

对象适配器类适配器的主要区别在于传递请求的方式:对象适配器使用组合的方式,类适配器使用继承的方式;

装饰者模式适配器模式的区别:装饰者模式的工作在于扩展其包装的对象的行为或责任,适配器模式仅仅进行接口的转换,允许客户使用新的库和子集合,无须改变原来的任何代码;

外观模式:提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

外观模式适配器模式的区别:

外观模式的意图在于简化接口,避免客户与子系统之间的紧耦合;

适配器模式将一个或多个类接口,变成客户所期望的一个接口,其意图在于将接口转换成其他接口;

“最少知识”原则:设计一个系统的过程中,减少对象之间的交互,不要让太多的类耦合在一起。对于最少知识原则,对任何对象而言,在该对象的方法内,我们应该调用属于以下范围内的方法:

该对象本身;

被当作输入参数而传递进来的对象;

该方法所创建或实例化的任何对象(即局部变量);

该对象的任何组件;

八. 模板方法模式

模板方法模式:在一个方法中定义一个算法的步骤,而将某些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

当子类必须提供算法中的某个方法或步骤的实现时,使用抽象方法;如果算法的这个部分是可选的,就用钩子(钩子即为在抽象类中,什么事情都不做的一个具体方法,可以让子类有能力对算法的不同点进行挂钩,且由子类自行决定是否需要挂钩);

好莱坞原则:允许低层组件将自己挂钩到系统上,但高层组件会决定什么时候、怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式,就是“别调用我们,我们会调用你”。

高层组件可以理解为基类(用于控制算法实现);

低层组件可以理解为派生类(用于实现部分高层组件的具体实现);

策略模式模板方法模式的对比:

相同点:两者的作用都在于对算法的封装

不同点:策略模式使用组合的方式,模板方法模式使用继承的方式;

九. 迭代器模式与组合模式

迭代器模式:提供一种方法,顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。在该模式下迭代器提供了一种方法,可以顺序访问一个聚集对象中的元素,而又不用知道内部是如何表示的。

迭代器的两个重要方法:

hasNext():告诉我们在这个聚合中是否还有更多的元素;

next():返回这个聚合中的下一个对象;

迭代器意味着没有次序。只是取出所有的元素,并不表示取出元素的先后就代表元素的大小次序。

单一责任原则:一个类应该只有一个引起变化的原因;

组合模式:允许将对象组合成树形结构来表现“整体 / 部分”的层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。核心思路是递归

组合模式的 UML 图如下所示:



客户 (Client):使用组合 (Componet) 的接口,对组合中的对象进行操作;

组合 (Component) :为组合 (Componet) 中的所有对象定义一个接口,为组件 (Composite) 叶节点 (Leaf) 提供部分默认方法;

叶节点 (Leaf) :没有子节点的组件;叶节点 (Leaf) 通过实现组件 (Composite) 的行为,定义了组合内元素的行为;

组件 (Composite) :定义具有子节点的组件的行为;组件 (Composite) 也实现了叶节点 (Leaf) 相关的操作(且某些操作对组件意义不大,可能会产生异常);

组合、组件、叶节点的关系:

组合 (Component) 包含组件 (Composite)

组件 (Composite) 包含两种:组合 (Component) (指组件中,可以包含一个子组合,含义类似于递归)和叶节点 (Leaf)

(本文持续更新ing….)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 设计模式 对象 oo