Categorygithub.com/aapanhao/headfirstdesignpatterns
module
0.0.0-20240531022902-40c177025843
Repository: https://github.com/aapanhao/headfirstdesignpatterns.git
Documentation: pkg.go.dev

# README

headFirstDesignPatterns

最近在阅读《headFirstDesignPatterns》这本书,代码是java写的,最近也在实践go,想法是用go来实现书上的例子 一方面学习go用法,一方面学习设计模式 目标:每种设计模式使用场景,书中例子描述,画出类的关系图,写出代码

设计原则:

1、多用组合,少用继承

理解:为了复用行为,可以使用组合的方式:例如策略模式,观察者模式,装饰模式 都是使用的类的组合,从而获取更加丰富的行为。 (装饰模式虽然也是继承,但是这是为了保障类型相同,而非继承行为) 这样可以保障代码的松耦合。达到对修改关闭,而对扩展开放。

2、基于接口编程,而非实现编程。

使用接口更加灵活,达到运行时的多态。

3、最少朋友原则

知道的越多,越容易受到改变

SOLID S 单一原则,应用在设计类 O 开闭原则,实现功能系统,最终要达到的目的,对扩展开发,对修改关闭 L 里氏替代原则,子类可以完全替代父类 I 接口隔离 最少朋友原则?不应该知道多余的信息(方法) D 依赖倒置,上层(核心组件)和下层(灵活组件)都依赖抽象(或者接口),指定一个框架,更易扩展开发

不同模式适用场景:

策略模式

一个实体类,需要有一些附加行为。 书中例子:不同鸭子类;有不同的飞的行为,不同的叫的行为。 在鸭子类中,依赖行为接口,利用组合的方式获取到了行为。也就是委托给行为类。 代码:chapter_1_strategy

观察者模式

一个主题,有信息变化时,通知到消费者。 书中的例子:主题,天气数据变化;不同的布告板,根据数据进行展示。 在主题类中,依赖观察者接口,可以注册与删除实际的观察者,当有数据变化时,通知注册的观察者。 代码:chapter_2_observer

装饰模式

在原来基础上进行装饰、包装,来增加行为 书中例子:饮料,可以加入不同的调料,进行收费。 饮料类,不同的饮料是一些子类(例如 茶、咖啡),调料是一些子类,通过递归方式计算价格。 代码:chapter_3_decorate

工厂模式

将实例化逻辑,放在单独的方法或类中创建,已达到OCP(对扩展开发、对修改关闭的原则) 针对于抽象编程,而非实现编程;定义框架,依赖接口,更易扩展和修改。soft 所有工厂都是用来封装对象的,所以封装(实现)对象,要想到工厂。 写之前还是要根据单一原则,制定好类,每个类的职责 代码:chapter_4_factory

简单工厂模式

将创建不同行为(或实体)逻辑,原来是在类中封装,现在将这部分变化的单独抽离出来。 书中的例子:首先分为两个类:PizzaStore(负责销售pizza), Pizza(Pizza实体类),需要根据不同的type创建pizza 所以分离出SimplePizzaFactory类,专门用于创建Pizza

工厂方法模式

将创建不同行为(或实体)的逻辑,放在子类中 PizzStore作为父类,NYPizzaStore、ChicagoPizzaStore作为子类,复写CreatePizza方法,创建自己的Pizza 这种在类中实现,叫做虚拟方法,但go中没有 "对于类型T或* T的值x(其中T不是指针或接口类型),x.f表示存在f的T中最浅深度的字段或方法"

抽象工厂

使用了工厂方法,工厂方法只需要实例化一个产品,而抽象工厂需要实例化多个产品(产品家族) PizzaIngredientFactory作为抽象类,NYPizzaIngredientFactory和ChicagoPizzaIngredientFactory 实现其中的抽象方法 创建不同的实例对象,如Sauce、Cheese、Claim 等 原Pizza注入PizzaIngredientFactory 原PizzaStore使用不同PizzaIngredientFactory

单件模式

类只有一个实例化对象,并提供一个全局访问点。 书中例子:巧克力工厂。 做法是类中有个类对象,构建函数私有(java特性),使用一个静态函数(类可以访问)创建一个对象 判断是否已经实例化 注意多线程创建,可能会创建多个对象,所以需要加锁(双重锁可以保证性能,又保证安全) go中没有类的概念,只有结构体,所以使用包中变量的方式,来提供一个全局访问点;使用一个可导出的函数,来只实例化一个对象。 为了让其他调用方不能实例化结构体,可以将结构体设置为不可导的(也只限于其他包访问,自己的包还是可以实例化)。 在创建时可以使用sync.once 保证只运行一次。 代码:chapter_5_singleton

命令模式

将请求包装成对象(将灯包装一层为实现命令接口),以便调用方方便的使用不同的命令。命令模式也支持撤销。 书中例子:不同家具,封装为命令;核心框架是遥控器,遥控器来控制不同命令。 遥控器依赖Command接口,不同家具实现了Command接口,通过组合来解耦。 还有宏命令形式,封装了多个命令; 命令模式和策略模式区别,命令在应用场景上更多,同种类的命令(行为),而策略是不同种类的行为; 所以命令这种模式可以用于队列请求,因为队列只需处理命令接口的execute方法即可(就像处理kafka的一个消息一样) 也很像观察者模式,主题和观察者是解耦的,主题只需要处理观察者接口的update方法接口。 代码:chapter_6_command

适配器模式

将一个类的接口,转化为客户(核心组件)期望的另一个接口,以方便使用 适配器中有要适配的对象 让客户端从实现中解耦的意思(也就是依赖接口而非实现):客户(核心组件)依赖接口(抽象)进行编程,需要把实例当成一个变量注入进来,这样实例只需要实现了接口,就可以在核心组件中运行,从而实现可扩展,灵活的方式。 代码:chapter_7_adapter

外观模式

改变接口的原因是为了简化接口 外观模式和命令模式中的宏命令有点像,都是为了简化(批量)处理多个命令(设备)。但是命令模式中宏命令,需要每个设备都满足命令接口 外观模式相当于加了一层简化,将复杂隐藏在背后(接口隔离,浅调用、深实现) 代码:chapter_7_facade 适配器和外观都是包装原类,适配器目的是转换,外观目的是简化。都可以将客户与组件解耦。

模板模式

看起来像工厂方法模式,父类定义模版,子类覆盖其中一些特别的点 模板方法定义一个算法步骤,允许子类为其中一个或多个步骤提供实现。 保护算法核心步骤,子类实现某些特定步骤。 由于go特性,虚拟方法使用最浅深度方法,所以不能直接嵌入使用,决定了大多时候要注入(当成参数传进入) 所以不光继承可以实现模板模式,静态方法中,注入参数,满足接口方式也可以实现(策略模式) 模板方法站在客户(核心)的角度来实现,策略模式站着组件(灵活)的角度来实现 代码:chapter_8_template

迭代器模式

想起来了 包装一层(方便客户端使用):命令模式,适配器,外观;适用的场景不一样 迭代器接口,hasNext Next 将满足迭代器接口的实例,返回给客户端 不是都有包装返回,例如Iterator包装了Dinner,Dinner方法可以返回Iterator 代码:chapter_9_iterator

组合模式

对象以树形结构组合在一起,客户可以一致的处理单个对象和对象组合 组合和命令模式相似的是,都是以相同(一致)的方式处理对象,不同的是命令模式的接口只有一个方法,组合模式的接口有多个方法。并且组合模式可以进行对象集合方便操作,命令是单个对象(虽然可以使用宏命令处理多个命令)。命令模式就像树全是叶子节点。组合模式是一棵树,有叶子节点有子树。 chapter_9_composite

状态模式

在对象内部状态改变时,改变其行为 chapter_10_state

FSM 有限状态机

状态,事件,动作 定义状态(state), 事件(event), 行动(callback) 事件:触发条件和状态转换(需要初始状态和事件描述一致,才会触发,并且转换到下一行为) 行动:事件发生前后的行动(单独事件或整体事件),状态变化前后的行动(单独状态或整体状态)

FSM并不替代状态模式,而是用状态转换图替代状态转换中if、else的操作,并且展示清晰,便于理解 FSM:适合有限状态,状态转换明确;状态模式适用于复杂多变状态转换(扩展性好) chapter_10_fsm

代理模式

为另一个对象提供一个替身,以控制对其进行的访问。就像远程代理中的Stub对象。 远程代理,远程访问对象。还有虚拟代理,访问开销大的对象。保护代理,安全访问资源。 真实对象和代理对象,都实现了同一接口。那么客户端可以像处理真实对象一样,处理代理对象。代理对象进行控制,真实对象实际做事。 通过包装,替换对象,场景远程、虚拟、保护;装饰器是增加行为。

进度

04-30 阅读了前三章:策略模式,观察者模式,装饰模式 go run main.go 只会编译main文件,可能找不到相同目录下其他变量;一种解决是使用go run . 另一种解决是将其他文件放在单独文件夹下。

05-01 go结构的构造函数,可以自己定义一个函数,然后使用该函数创建对象

05-04 转换能力,将书中例子,转换为自己理解,比如 有哪些结构体,结构体有什么字段方法,有什么接口。 坚持下去,坚持自律,就会获得新生

05-09 又一次感受到,基于接口编程而不是实现编程,为了写出更加灵活的代码(对扩展开发,对修改关闭),搭出依赖接口的框架,具体实现(实例化的对象)往里填充。

05-12 很多模式通常是使用包装后的类来返回给客户端,客户端进行操作;例如命令模式,适配器、外观模式 但是有些模式中,不是包装,而是内部封装一个接口,给客户端使用;例如迭代器模式,封装的迭代器就像原来类的一个方便实现;还有工厂模式

05-20 java中rmi,类似go中grpc 四部分:服务,请求方法,请求参数,响应参数 go grpc 定义proto,使用protoc生成 两个.pb文件 server: 实现接口实现方法,注册服务,监听端口运行; Client:新建端口连接,新建:客户端,方法,请求,响应;

05-22 多个if的替换,不仅仅可以用工厂模式替换,还可以用状态模式 两个状态,ImageLoad,ImageNotLoad, currentState,通过状态转换来改变行为

上述所有模式的类图:https://k8naup2m4f.feishu.cn/docx/IKTzdpN7ioUhkIxikOHc3ZQonsg

网上例子:https://refactoringguru.cn/design-patterns

# Packages

No description provided by the author