设计模式的一些使用原则
设计模式的一些使用原则
之前把23种设计模式结合golang代码总结了一下,但这23种设计模式相当于武功招式,只掌握了武功招式没有内功心法是没办法发挥其作用,你只会盲目的去套用招式这往往会得到相反的效果,我们经常看到过度设计导致代码不但复杂而且性能低下。这一篇文章就总结一下为什么要使用23种设计模式。
用好设计模式首先要了解面向对象:
面向对象设计封装(Encapsulation)封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。
封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如 Java 中的 private、protected、public 关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
抽象(Abstraction)抽象是从具体事物中提取共性,形成更高层次的概念。
计算机科学中的抽象是通过隐藏细节,简化复杂系统的 ...
结合Golang聊聊23种设计模式---行为型(3)
结合Golang聊聊23种设计模式—行为型(3)责任链模式责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
责任链模式的英文翻译是 Chain Of Responsibility Design Pattern。
在 GoF 的《设计模式》中,它是这么定义的:Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
翻译成中文就是:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
这么说比较抽象,我用更加容易理解的话来进一步解读一下。在 ...
结合Golang聊聊23种设计模式---行为型(2)
结合Golang聊聊23种设计模式—行为型(2)策略模式策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
翻译成中文就是:定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
我们知道,工厂模式是解耦对象的创建和使用,观察者模式是解耦观察者和被观察者。策略模式跟两者类似,也能起到解耦的作用,不过,它解耦的是策略的定义、创建、使用这三部分。
为什么要使用策略模式策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
我们可以利用策略模式来移除 if-else ...
结合Golang聊聊23种设计模式---行为型(1)
结合Golang聊聊23种设计模式—行为型(1)
我们常把 23 种经典的设计模式分为三类:创建型、结构型、行为型。前面我们已经学习了创建型和结构型,从今天起,我们开始学习行为型设计模式。我们知道,创建型设计模式主要解决“对象的创建”问题,结构型设计模式主要解决“类或对象的组合或组装”问题,那行为型设计模式主要解决的就是“类或对象之间的交互”问题。
行为型设计模式比较多,有 11 个,几乎占了 23 种经典设计模式的一半。它们分别是:观察者模式、模板模式、策略模式、职责链模式、状态模式、迭代器模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式。
观察者模式观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。在 GoF 的《设计模式》一书中,它的定义是这样的:Define a one-to-many dependency between objects so that when one object changes state, all its dependents are ...
结合Golang聊聊23种设计模式---结构型(2)
结合Golang聊聊23种设计模式—结构型(2)适配器模式适配器模式的英文翻译是 Adapter Design Pattern。顾名思义,这个模式就是用来做适配的
为什么要使用适配器模式适配器模式可以将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。
代码示例这里有一段客户端代码, 用于接收一个对象 (Lightning 接口) 的部分功能, 不过我们还有另一个名为 adaptee 的对象 (Windows 笔记本), 可通过不同的接口 (USB 接口) 实现相同的功能
这就是适配器模式发挥作用的场景。 我们可以创建这样一个名为 adapter 的结构体:
遵循符合客户端期望的相同接口 (Lightning 接口)。
可以适合被适配对象的方式对来自客户端的请求进行 “翻译”。 适配器能够接受来自 Lightning 连接器的信息, 并将其转换成 USB 格式的信号, 同时将信号传递给 Windows 笔记本的 USB 接口。
...
结合Golang聊聊23种设计模式---结构型(1)
结合Golang聊聊23种设计模式—结构型(1)结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。结构型模式包括:代理模式、桥接模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式。
代理模式代理模式(Proxy Design Pattern)它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。
为什么要使用代理模式第一,防止框架如监控、统计、鉴权、限流、事务、幂等、日志,缓存等代码侵入到业务代码中,跟业务代码高度耦合。如果未来需要替换这个框架,那替换的成本会比较大。
第二,框架代码跟业务代码无关,本就不应该放到一个类中。业务类最好职责更加单一,只聚焦业务处理。
代理类负责在业务代码执行前后附加其他逻辑代码,并通过委托的方式调用原始类来执行业务代码。具体的代码实现如下所示:
Nginx 这样的 Web 服务器可充当应用程序服务器的代理:
提供了对应用程序服务器的受控访问权限。
可限制速度。
可缓存请求。
server.go: 主体12345package maintype server interfac ...
结合Golang聊聊23种设计模式---创建型
结合Golang聊聊23种设计模式—创建型
将不要过度设计也不要随意堆砌烂代码写在前面设计模式要干的事情就是解耦,也就是利用更好的代码结构将一大坨代码拆分成职责更单一的小类,让其满足高内聚低耦合等特性。创建型模式是将创建和使用代码解耦,结构型模式是将不同的功能代码解耦,行为型模式是将不同的行为代码解耦。而解耦的主要目的是应对代码的复杂性。设计模式就是为了解决复杂代码问题而产生的。因此,对于复杂代码,比如项目代码量多、开发周期长、参与开发的人员多,我们前期要多花点时间在设计上,越是复杂代码,花在设计上的时间就要越多。 不仅如此,每次提交的代码,都要保证代码质量,都要经过足够的思考和精心的设计,这样才能避免烂代码效应(每次提交的代码质量都不是太好,最终积累起来整个项目的质量就变得很差)。相反,如果你参与的只是一个简单的项目,代码量不多,开发人员也不多,那简单的问题用简单的解决方案就好,不要引入过于复杂的设计模式,将简单问题复杂化。
单例模式为什么要使用单例?单例设计模式(Singleton Design Pattern)理解起来非常简单。一个类只允许创建一个对象(或者实例),那这个类就是 ...
Mysql--如何实现高可用
Mysql 如何实现高可用主备一致客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行。这样可以保持节点 B 和 A 的数据是相同的。
接下来,我们再看看节点 A 到 B 这条线的内部流程是什么样的。图 2 中画出的就是一个 update 语句在节点 A 执行,然后同步到节点 B 的完整流程图。
备库 B 跟主库 A 之间维持了一个长连接。主库 A 内部有一个线程,专门用于服务备库 B 的这个长连接。一个事务日志同步的完整过程是这样的:
在备库 B 上通过 change master 命令,设置主库 A 的 IP、端口、用户名、密码,以及要从哪个位置开始请求 binlog,这个位置包含文件名和日志偏移量。
在备库 B 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io_thread 和 sql_thread。其中 io_thread 负责与主库建立连接。
主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog,发给 B。
备库 B 拿到 binlog 后,写到本地文件,称 ...
Mysql--Join
Mysql Join我们 DBA 不让使用 join,使用 join 有什么问题呢?如果有两个大小不同的表做 join,应该用哪个表做驱动表呢?
Index Nested-Loop Join1select * from t1 straight_join t2 on (t1.a=t2.a);
如果直接使用 join 语句,MySQL 优化器可能会选择表 t1 或 t2 作为驱动表,这样会影响我们分析 SQL 语句的执行过程。所以,为了便于分析执行过程中的性能问题,我改用 straight_join 让 MySQL 使用固定的连接方式执行查询,这样优化器只会按照我们指定的方式去 join。在这个语句里,t1 是驱动表,t2 是被驱动表。
现在,我们来看一下这条语句的 explain 结果。
可以看到,在这条语句里,被驱动表 t2 的字段 a 上有索引,join 过程用上了这个索引,因此这个语句的执行流程是这样的:
从表 t1 中读入一行数据 R;
从数据行 R 中,取出 a 字段到表 t2 里去查找;
取出表 t2 中满足条件的行,跟 R 组成一行,作为结果集的一部分;
重复执行 ...
Mysql--临时表和group by
Mysql 临时表和group by临时表临时表的特点
建表语法是 create temporary table …。
一个临时表只能被创建它的 session 访问,对其他线程不可见。所以,图中 session A 创建的临时表 t,对于 session B 就是不可见的。
临时表可以与普通表同名。
session A 内有同名的临时表和普通表的时候,show create 语句,以及增删改查语句访问的是临时表。
show tables 命令不显示临时表。
由于临时表只能被创建它的 session 访问,所以在这个 session 结束的时候,会自动删除临时表。也正是由于这个特性,临时表就特别适合我们文章开头的 join 优化这种场景。为什么呢?
原因主要包括以下两个方面:
不同 session 的临时表是可以重名的,如果有多个 session 同时执行 join 优化,不需要担心表名重复导致建表失败的问题。
不需要担心数据删除问题。如果使用普通表,在流程执行过程中客户端发生了异常断开,或者数据库发生异常重启,还需要专门来清理中间过程中生成的数据表。而临时表由于会自动回收,所以 ...