设计模式基础
文章平均质量分 92
小猪快跑22
专注于Java以及Android
展开
-
接口vs抽象类的区别?
在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。比如,我们可以使用接口来实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则,使用抽象类来实现面向对象的继承特性和模板设计模式等等。不过,并不是所有的面向对象编程语言都支持这两个语法概念,比如,C++ 这种编程语言只支持抽象类,不支持接口;而像 Python 这样的动态编程语言,既不支持抽象类,也不支持接口。尽管有些编程语言没有提供现成的语法来支持接口和抽象类,我们仍然原创 2020-12-14 18:41:39 · 180 阅读 · 0 评论 -
策略模式(下):如何实现一个支持给不同大小文件排序的小程序?
结合给文件排序这样一个具体的例子,来详细讲一讲策略模式的设计意图和应用场景。除此之外,我还会通过一步一步地分析、重构,给你展示一个设计模式是如何“创造”出来的。通过今天的学习,你会发现,设计原则和思想其实比设计模式更加普适和重要,掌握了代码的设计原则和思想,我们甚至可以自己创造出来新的设计模式。问题与解决思路假设有这样一个需求,希望写一个小程序,实现对一个文件进行排序的功能。文件中只包含整型数,并且,相邻的数字通过逗号来区隔。如果由你来编写这样一个小程序,你会如何来实现呢?你可以把它当作面试题,先自己原创 2020-12-03 09:23:25 · 193 阅读 · 0 评论 -
策略模式(上):如何避免冗长的if-else/switch分支判断代码?
策略模式,在实际的项目开发中,这个模式也比较常用。最常见的应用场景是,利用它来避免冗长的 if-else 或 switch 分支判断。不过,它的作用还不止如此。它也可以像模板模式那样,提供框架的扩展点等等。对于策略模式,我们分两节课来讲解。今天,我们讲解策略模式的原理和实现,以及如何用它来避免分支判断逻辑。下一节课,我会通过一个具体的例子,来详细讲解策略模式的应用场景以及真正的设计意图。策略模式的原理与实现策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》原创 2020-12-03 09:23:09 · 242 阅读 · 0 评论 -
职责链模式(下):框架中常用的过滤器、拦截器是如何实现的?
我们之前学习了职责链模式的原理与实现,并且通过一个敏感词过滤框架的例子,展示了职责链模式的设计意图。本质上来说,它跟大部分设计模式一样,都是为了解耦代码,应对代码的复杂性,让代码满足开闭原则,提高代码的可扩展性。除此之外,我们还提到,职责链模式常用在框架的开发中,为框架提供扩展点,让框架的使用者在不修改框架源码的情况下,基于扩展点添加新的功能。实际上,更具体点来说,职责链模式最常用来开发框架的过滤器和拦截器。今天,我们就通过 Servlet Filter、Spring Interceptor 这两个 Ja原创 2020-12-03 09:22:38 · 437 阅读 · 2 评论 -
如何实现可灵活扩展算法的敏感信息过滤框架?
今天,我们主要讲解职责链模式的原理和实现。除此之外,我还会利用职责链模式,带你实现一个可以灵活扩展算法的敏感词过滤框架。下一节课,我们会更加贴近实战,通过剖析 Servlet Filter、Spring Interceptor 来看,如何利用职责链模式实现框架中常用的过滤器、拦截器。职责链模式的原理和实现职责链模式的英文翻译是 Chain Of Responsibility Design Pattern。在 GoF 的《设计模式》中,它是这么定义的:Avoid coupling the sender原创 2020-12-02 15:38:15 · 264 阅读 · 0 评论 -
观察者模式(下):如何实现一个异步非阻塞的EventBus框架?
观察者模式 : 同步阻塞是最经典的实现方式,主要是为了代码解耦;异步非阻塞除了能实现代码解耦之外,还能提高代码的执行效率;进程间的观察者模式解耦更加彻底,一般是基于消息队列来实现,用来实现不同进程间的被观察者和观察者之间的交互。异步非阻塞观察者模式的简易实现对于异步非阻塞观察者模式,如果只是实现一个简易版本,不考虑任何通用性、复用性,实际上是非常容易的。我们有两种实现方式。其中一种是:在每个 handleRegSuccess() 函数中创建一个新的线程执行代码逻辑;另一种是:在 UserControl原创 2020-12-02 14:43:02 · 433 阅读 · 2 评论 -
观察者模式(上):详解各种应用场景下观察者模式的不同实现方式
观察者模式,根据应用场景的不同,观察者模式会对应不同的代码实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。今天我会重点讲解原理、实现、应用场景。下一节课,我会带你一块实现一个基于观察者模式的异步非阻塞的 EventBus,加深你对这个模式的理解。原理及应用场景剖析观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。在 GoF 的《设计模式》一书中,它的定义原创 2020-12-02 14:00:08 · 1237 阅读 · 1 评论 -
工厂模式(下):如何设计实现一个Dependency Injection框架?
当创建对象是一个“大工程”的时候,我们一般会选择使用工厂模式,来封装对象复杂的创建过程,将对象的创建和使用分离,让代码更加清晰。那何为“大工程”呢?上一节课中我们讲了两种情况,一种是创建过程涉及复杂的 if-else 分支判断,另一种是对象创建需要组装多个其他类对象或者需要复杂的初始化过程。再来讲一个创建对象的“大工程”,依赖注入框架,或者叫依赖注入容器(Dependency Injection Container),简称 DI 容器。在今天的讲解中,我会带你一块搞清楚这样几个问题:DI 容器跟我们讲的工原创 2020-12-02 11:46:27 · 182 阅读 · 0 评论 -
工厂模式(上):我为什么说没事不要随便用工厂模式创建对象?
一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。不过,在 GoF 的《设计模式》一书中,它将简单工厂模式看作是工厂方法模式的一种特例,所以工厂模式只被分成了工厂方法和抽象工厂两类。实际上,前面一种分类方法更加常见,所以,在今天的讲解中,我们沿用第一种分类方法。在这三种细分的工厂模式中,简单工厂、工厂方法原理比较简单,在实际的项目中也比较常用。而抽象工厂的原理稍微复杂点,在实际的项目中相对也不常用。所以,我们今天讲解的重点是前两种工厂模式。对于抽象工厂,你稍微了解一下即可。除此之原创 2020-12-02 11:32:56 · 448 阅读 · 0 评论 -
装饰器模式:通过剖析Java IO类库源码学习装饰器模式
桥接模式有两种理解方式。第一种理解方式是“将抽象和实现解耦,让它们能独立开发”。这种理解方式比较特别,应用场景也不多。另一种理解方式更加简单,类似“组合优于继承”设计原则,这种理解方式更加通用,应用场景比较多。不管是哪种理解方式,它们的代码结构都是相同的,都是一种类之间的组合关系。Java IO 类的“奇怪”用法Java IO 类库非常庞大和复杂,有几十个类,负责 IO 数据的读取和写入。如果对 Java IO 类做一下分类,我们可以从下面两个维度将它划分为四类。具体如下所示:针对不同的读取和写入场原创 2020-12-02 11:07:29 · 209 阅读 · 0 评论 -
桥接模式:如何实现支持不同类型和渠道的消息推送系统?
桥接模式的代码实现非常简单,但是理解起来稍微有点难度,并且应用场景也比较局限,所以,相当于代理模式来说,桥接模式在实际的项目中并没有那么常用,你只需要简单了解,见到能认识就可以,并不是我们学习的重点。桥接模式的原理解析桥接模式,也叫作桥梁模式,英文是 Bridge Design Pattern。这个模式可以说是 23 种设计模式中最难理解的模式之一了。我查阅了比较多的书籍和资料之后发现,对于这个模式有两种不同的理解方式。当然,这其中“最纯正”的理解方式,当属 GoF 的《设计模式》一书中对桥接模式的定原创 2020-12-02 10:57:48 · 217 阅读 · 0 评论 -
代理模式 代理在RPC、缓存、监控等场景中的应用
单例模式用来创建全局唯一的对象。工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象。原型模式针对创建成本比较大的对象,利用对已有对象进行复制的方式进行创建,以达到节省创建时间的目的。从今天起,我们开始学习另外一种类型的设计模式:结构型模式。结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。结构型模式包括:代理模式、桥原创 2020-12-02 10:40:18 · 223 阅读 · 0 评论 -
适配器模式:代理、适配器、桥接、装饰,这四个模式有何区别?
前面几节课我们学习了代理模式、桥接模式、装饰器模式,今天,我们再来学习一个比较常用的结构型模式:适配器模式。这个模式相对来说还是比较简单、好理解的,应用场景也很具体,总体上来讲比较好掌握。关于适配器模式,今天我们主要学习它的两种实现方式,类适配器和对象适配器,以及 5 种常见的应用场景。同时,我还会通过剖析 slf4j 日志框架,来给你展示这个模式在真实项目中的应用。除此之外,在文章的最后,我还对代理、桥接、装饰器、适配器,这 4 种代码结构非常相似的设计模式做简单的对比,对这几节内容做一个简单的总结。原创 2020-12-02 10:20:38 · 328 阅读 · 0 评论 -
原型模式:如何最快速地clone一个HashMap散列表?
对于熟悉 JavaScript 语言的前端程序员来说,原型模式是一种比较常用的开发模式。这是因为,有别于 Java、C++ 等基于类的面向对象编程语言,JavaScript 是一种基于原型的面向对象编程语言。即便 JavaScript 现在也引入了类的概念,但它也只是基于原型的语法糖而已。不过,如果你熟悉的是 Java、C++ 等这些编程语言,那在实际的开发中,就很少用到原型模式了。今天的讲解跟具体某一语言的语法机制无关,而是通过一个 clone 散列表的例子带你搞清楚:原型模式的应用场景,以及它的两种实转载 2020-12-02 09:16:20 · 201 阅读 · 0 评论 -
建造者模式:详解构造函数、set方法、建造者模式三种对象创建方式
Builder 模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式。实际上,建造者模式的原理和代码实现非常简单,掌握起来并不难,难点在于应用场景。比如,你有没有考虑过这样几个问题:直接使用构造函数或者配合 set 方法就能创建对象,为什么还需要建造者模式来创建呢?建造者模式和工厂模式都可以创建对象,那它们两个的区别在哪里呢?为什么需要建造者模式?在平时的开发中,创建一个对象最常用的方式是,使用 new 关键字调用类的构造函数来完成。我的问题是,什么情况下这种方式就不适用了,就需要采用建造者原创 2020-12-01 18:44:44 · 508 阅读 · 0 评论 -
单例模式(下):如何设计实现一个集群环境下的分布式单例模式?
我们针对单例模式,讲解了单例的应用场景、几种常见的代码实现和存在的问题,并粗略给出了替换单例模式的方法,比如工厂模式、IOC 容器。今天,我们再进一步扩展延伸一下,一块讨论一下下面这几个问题:● 如何理解单例模式中的唯一性?● 如何实现线程唯一的单例?● 如何实现集群环境下的单例?● 如何实现一个多例模式?今天的内容稍微有点“烧脑”,希望你在看的过程中多思考一下。话不多说,让我们正式开始今天的学习吧!如何理解单例模式中的唯一性?首先,我们重新看一下单例的定义:“一个类只允许创建唯一一个对象(或原创 2020-12-01 18:31:49 · 1042 阅读 · 0 评论 -
单例模式(中):我为什么不推荐使用单例模式?又有何替代方案?
尽管单例是一个很常用的设计模式,在实际的开发中,我们也确实经常用到它,但是,有些人认为单例是一种反模式(anti-pattern),并不推荐使用。所以,今天,我就针对这个说法详细地讲讲这几个问题:单例这种设计模式存在哪些问题?为什么会被称为反模式?如果不用单例,该如何表示全局唯一类?有何替代的解决方案?单例存在哪些问题?大部分情况下,我们在项目中使用单例,都是用它来表示一些全局唯一类,比如配置信息类、连接池类、ID 生成器类。单例模式书写简洁、使用方便,在代码中,我们不需要创建对象,直接通过类似 IdG原创 2020-12-01 18:25:12 · 666 阅读 · 0 评论 -
理论十二:如何通过封装、抽象、模块化、中间层等解耦代码?
。对于大型重构来说,今天我们重点讲解最有效的一个手段,那就是“解耦”。解耦的目的是实现代码高内聚、松耦合。关于解耦,我准备分下面三个部分来给你讲解。● “解耦”为何如此重要?● 如何判定代码是否需要“解耦”?● 如何给代码“解耦”?“解耦”为何如此重要?软件设计与开发最重要的工作之一就是应对复杂性。人处理复杂性的能力是有限的。过于复杂的代码往往在可读性、可维护性上都不友好。那如何来控制代码的复杂性呢?手段有很多,我个人认为,最关键的就是解耦,保证代码松耦合、高内聚。如果说重构是保证代码质量不至于腐原创 2020-12-01 18:01:45 · 911 阅读 · 0 评论 -
理论十一:如何用迪米特法则(LOD)实现“高内聚、松耦合”?
前言● 什么是“高内聚、松耦合”?● 如何利用迪米特法则来实现“高内聚、松耦合”?● 有哪些代码设计是明显违背迪米特法则的?对此又该如何重构?何为“高内聚、松耦合”?“高内聚、松耦合”是一个非常重要的设计思想,能够有效地提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。实际上,在前面的章节中,我们已经多次提到过这个设计思想。很多设计原则都以实现代码的“高内聚、松耦合”为目的,比如单一职责原则、基于接口而非实现编程等。实际上,“高内聚、松耦合”是一个比较通用的设计思想,可以用来指导不同粒原创 2020-12-01 17:32:59 · 249 阅读 · 0 评论 -
控制反转、依赖反转、依赖注入,这三者有何区别和联系?
依赖反转原则● “依赖反转”这个概念指的是“谁跟谁”的“什么依赖”被反转了?“反转”两个字该如何理解?● 我们还经常听到另外两个概念:“控制反转”和“依赖注入”。这两个概念跟“依赖反转”有什么区别和联系呢?它们说的是同一个事情吗?● 如果你熟悉 Java 语言,那 Spring 框架中的 IOC 跟这些概念又有什么关系呢?控制反转(IOC)在讲“依赖反转原则”之前,我们先讲一讲“控制反转”。控制反转的英文翻译是 Inversion Of Control,缩写为 IOC。此处我要强调一下,如果你是原创 2020-12-01 17:01:02 · 873 阅读 · 0 评论 -
接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
如何理解“接口隔离原则”?接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。实际上,“接口”这个名词可以用在很多场合原创 2020-12-01 16:48:59 · 263 阅读 · 1 评论 -
如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
在上一节课中,我们学习了单一职责原则。今天,我们来学习 SOLID 中的第二个原则:开闭原则。我个人觉得,开闭原则是 SOLID 中最难理解、最难掌握,同时也是最有用的一条原则。之所以说这条原则难理解,那是因为,“怎样的代码改动才被定义为‘扩展’?怎样的代码改动才被定义为‘修改’?怎么才算满足或违反‘开闭原则’?修改代码就一定意味着违反‘开闭原则’吗?”等等这些问题,都比较难理解。之所以说这条原则难掌握,那是因为,“如何做到‘对扩展开放、修改关闭’?如何在项目中灵活地应用‘开闭原则’,以避免在追求扩展性转载 2020-12-01 16:04:17 · 770 阅读 · 0 评论 -
里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
在上两节课中,我们学习了 SOLID 原则中的单一职责原则和开闭原则,这两个原则都比较重要,想要灵活应用也比较难,需要你在实践中多加练习、多加体会。今天,我们再来学习 SOLID 中的“L”对应的原则:里式替换原则。整体上来讲,这个设计原则是比较简单、容易理解和掌握的。今天我主要通过几个反例,带你看看,哪些代码是违反里式替换原则的?我们该如何将它们改造成满足里式替换原则?除此之外,这条原则从定义上看起来,跟我们之前讲过的“多态”有点类似。所以,我今天也会讲一下,它跟多态的区别。话不多说,让我们正式开始今原创 2020-12-01 15:39:07 · 277 阅读 · 0 评论 -
如何对接口鉴权这样一个功能开发做面向对象分析?
在上一节课中,针对接口鉴权功能的开发,我们讲了如何进行面向对象分析(OOA),也就是需求分析。实际上,需求定义清楚之后,这个问题就已经解决了一大半,这也是为什么我花了那么多篇幅来讲解需求分析。今天,我们再来看一下,针对面向对象分析产出的需求,如何来进行面向对象设计(OOD)和面向对象编程(OOP)。如何进行面向对象设计?我们知道,面向对象分析的产出是详细的需求描述,那面向对象设计的产出就是类。在面向对象设计环节,我们将需求描述转化为具体的类的设计。我们把这一设计环节拆解细化一下,主要包含以下几个部分:转载 2020-11-30 11:10:08 · 225 阅读 · 0 评论 -
为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
在上一节课中,我们讲了接口和抽象类,以及各种编程语言是如何支持、实现这两个语法概念的。今天,我们继续讲一个跟“接口”相关的知识点:基于接口而非实现编程。这个原则非常重要,是一种非常有效的提高代码质量的手段,在平时的开发中特别经常被用到。为了让你理解透彻,并真正掌握这条原则如何应用,今天,我会结合一个有关图片存储的实战案例来讲解。除此之外,这条原则还很容易被过度应用,比如为每一个实现类都定义对应的接口。针对这类问题,在今天的讲解中,我也会告诉你如何来做权衡,怎样恰到好处地应用这条原则。话不多说,让我们正式原创 2020-11-27 16:00:36 · 356 阅读 · 0 评论