设计模式之美
in the way
这个作者很懒,什么都没留下…
展开
-
设计模式之美32--spring中用到的设计模式及思想
Spring框架蕴含的设计思想1.约定优于配置2.低侵入、松耦合3.模块化、轻量级4.再封装、再抽象原创 2020-09-01 22:05:09 · 119 阅读 · 0 评论 -
设计模式之美31--不变模式
Immutable模式,中文叫作不变模式,它并不属于经典的23种设计模式,但作为一种较常用的设计思路,可以总结为一种设计模式来学习。之前在理论部分,我们只稍微提到过Immutable模式,但没有独立的拿出来详细讲解,我们这里借Google Guava再补充讲解一下。一个对象的状态在对象创建之后就不再改变,这就是所谓的不变模式。其中涉及的类就是不变类(Immutable Class),对象就是不变对象(Immutable Object)。在Java中,最常用的不变类就是String类,String对象一旦创原创 2020-09-01 21:45:25 · 251 阅读 · 0 评论 -
设计模式之美30--23中设计模式总结
一:创建型设计模式**1.单例模式**单例模式用来创建全局唯一的对象。一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。单例有几种经典的实现方式,它们分别是:饿汉式、懒汉式、双重检测、静态内部类、枚举。尽管单例是一个很常用的设计模式,在实际的开发中,我们也确实经常用到它,但是,有些人认为单例是一种反模式(anti-pattern),并不推荐使用,主要的理由有以下几点:单例对OOP特性的支持不友好单例会隐藏类之间的依赖关系单例对代码的扩展性不友好单.原创 2020-08-30 10:32:09 · 230 阅读 · 0 评论 -
设计模式之美29--中介模式
定义: 中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。原来一个对象要跟n个对象交互,现在只需要跟一个中介对象交互,从而最小化对象之间的交互关系,降低了代码的复杂度,提高了代码的可读性和可维护性。提到中介模式,有一个比较经典的例子不得不说,那就是航空管制。为了让飞机在飞行的时候互不干扰,每架飞机都需要知道其他飞机每时每刻的位置,这就需要时刻跟其他飞机通信。飞机通信形成的通信网络就会无比复杂。这个时候,我们通原创 2020-08-30 10:25:43 · 122 阅读 · 0 评论 -
设计模式之美29--解释器模式
定义: 解释器模式为某个语言定义它的语法(或者叫文法)表示,并定义一个解释器用来处理这个语法。实际上,这里的“语言”不仅仅指我们平时说的中、英、日、法等各种语言。从广义上来讲,只要是能承载信息的载体,我们都可以称之为“语言”,比如,古代的结绳记事、盲文、哑语、摩斯密码等。要想了解“语言”表达的信息,我们就必须定义相应的语法规则。这样,书写者就可以根据语法规则来书写“句子”(专业点的叫法应该是“表达式”),阅读者根据语法规则来阅读“句子”,这样才能做到信息的正确传递。而我们要讲的解释器模式,其实就是用来实原创 2020-08-30 10:14:04 · 128 阅读 · 0 评论 -
设计模式之美28--命令模式
定义:命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。使用不多命令模式用的最核心的实现手段,是将函数封装成对象。但是,在大部分编程语言中,函数没法儿作为参数传递给其他函数,也没法儿赋值给变量。借助命令模式,我们可以将函数封装成对象。具体来说就是,设计一个包含这个函数的类,实例化一个对象传来传去,这样就可以实现把函数像对象一样使用。命令模式的主要作用和应用场景,是用来控制命原创 2020-08-30 10:00:33 · 80 阅读 · 0 评论 -
设计模式之美27--备忘录模式
定义: 在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态假设有这样一道面试题,希望你编写一个小程序,可以接收命令行的输入。用户输入文本时,程序将其追加存储在内存文本中;用户输入“:list”,程序在命令行中输出内存文本的内容;用户输入“:undo”,程序会撤销上一次输入的文本,也就是从内存文本中将上次输入的文本删除掉>hello>:listhello>world>:listhelloworld>:und原创 2020-08-29 16:20:44 · 141 阅读 · 0 评论 -
设计模式之美26--访问者模式,单分派,双分派
定义: 允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。一般来说,访问者模式针对的是一组类型不同的对象(PdfFile、PPTFile、WordFile)。不过,尽管这组对象的类型是不同的,但是,它们继承相同的父类(ResourceFile)或者实现相同的接口。在不同的应用场景下,我们需要对这组对象进行一系列不相关的业务操作(抽取文本、压缩等),但为了避免不断添加功能导致类(PdfFile、PPTFile、WordFile)不断膨胀,职责越来越不单一,以及避免频繁地添加功能导致的频繁代码修改,我原创 2020-08-29 11:54:32 · 181 阅读 · 0 评论 -
设计模式之美25--状态模式
状态机的实现方式有多种,除了状态模式,比较常用的还有 分支逻辑法 和 查表法。状态机又叫有限状态机,它有3个部分组成:状态、事件、动作。超级玛丽示例:1, 分之逻辑法class MarioStateMachine { private int score; private State currentState; public MarioStateMachine() { this.score = 0; this.currentState = S原创 2020-08-26 21:32:45 · 406 阅读 · 0 评论 -
设计模式之美24--责任链模式
在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。需求:员工请假一天 主管审批, 请假2-3天 经理审批,请假3-30 天cto审批, 大于30不通过public abstract class AbstractHandler { protected AbstractHandler next原创 2020-08-25 22:17:05 · 185 阅读 · 0 评论 -
设计模式之美23--模版模式,回调函数
模板方法模式定义:模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。这里的“算法”,我们可以理解为广义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,包含算法骨架的方法就是“模板方法”,这也是模板方法模式名字的由来。templateMethod()函数定义为final,是为了避免子类重写它。method1()和method2()定义为abstract,是为了强迫子类去实原创 2020-08-18 22:08:15 · 268 阅读 · 0 评论 -
设计模式之美22--观察者模式, EventBus
1,定义:观察者模式(Observer Design Pattern)也被称为发布订阅模式,在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(Message message);}原创 2020-08-17 22:02:17 · 204 阅读 · 0 评论 -
设计模式之美21--享元模式
1.享元模式的原理所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。具体来讲,当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这样可以减少内存中对象的数量,起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段)提取出来,设计成享元,让这些大量相似对象引用这些享元。这里我稍微解释一下,定义中的“原创 2020-08-17 21:46:18 · 133 阅读 · 0 评论 -
设计模式之美20--组合模式
组合模式用的很少组合模式跟我们之前讲的面向对象设计中的“组合关系(通过组合来组装两个类)”,完全是两码事。这里讲的“组合模式”,主要是用来处理树形结构数据。这里的“数据”,将一组对象组织(Compose)成树形结构,以表示一种“部分-整体”的层次结构。组合让客户端(在很多设计模式书籍中,“客户端”代指代码的使用者。)可以统一单个对象和组合对象的处理逻辑。‘假设我们有这样一个需求:设计一个类来表示文件系统中的目录,能方便地实现下面这些功能:动态地添加、删除某个目录下的子目录或文件;统计指定目录下的原创 2020-08-16 11:15:47 · 92 阅读 · 0 评论 -
设计模式之美19--门面模式
门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。适配器是做接口转换,解决的是原接口和目标接口不匹配的问题。门面模式做接口整合,解决的是多接口调用带来的问题假设我们刚刚提到的系统A是一个后端服务器,系统B是App客户端。App客户端通过后端服务器提供的接口来获取数据。我们知道,App和服务器之间是通过移动网络通信的,网络通信耗时比较多,为了提高App的响应速度,我们要尽量减少App与服务器之间的网络通信次数。假设,完成某个业务功能(比如显示某个页面信息)需要“依次”调用a、b、d三原创 2020-08-16 10:55:45 · 118 阅读 · 0 评论 -
设计模式之美18--适配器模式
这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是USB转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。// 类适配器: 基于继承public interface ITarget { void f1(); void f2();...原创 2020-08-16 10:20:30 · 195 阅读 · 0 评论 -
设计模式之美17--装饰器模式
**装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。**除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。1.代理模式和装饰者模式都是 代码增强这一件事的落地方案。前者个人认为偏重业务无关,高度抽象,和稳定性较高的场景(性能其实可以抛开不谈)。后者偏重业务相关,定制化诉求高,改动较频繁的场景。2.缓存这件事原创 2020-08-15 14:40:03 · 113 阅读 · 0 评论 -
设计模式之美16--原型模式
原型模式使用较少原型模式的原理与应用如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。2.原型模式的两种实现方法原型模式有两种实现方法,深拷贝和浅拷贝。浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对原创 2020-08-15 12:14:10 · 131 阅读 · 0 评论 -
设计模式之美15--建造者模式
如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合set()方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了。我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过set()方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造原创 2020-08-15 12:09:22 · 132 阅读 · 0 评论 -
设计模式之美14--工厂模式
简单工厂和工厂方法比较常用,抽象工厂的应用场景比较特殊,所以很少用到。简单工厂模式:当每个对象的创建逻辑都比较简单的时候,将多个对象的创建逻辑放到一个工厂类中. if else 创建不同的对象。工厂方法模式:a. 当每个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的简单工厂类时,将创建逻辑拆分得更细,每个对象的创建逻辑独立到各自的工厂类中。b. 避免很多 if-else 分支逻辑时抽象工厂模式:一个工厂生产多个产品。有多种分类方式,如方式要用一套工厂方法,方式二要用原创 2020-08-15 11:50:16 · 117 阅读 · 0 评论 -
设计模式之美13--单例模式
1.如何理解单例模式的唯一性?单例类中对象的唯一性的作用范围是“进程唯一”的。“进程唯一”指的是进程内唯一,进程间不唯一;“线程唯一”指的是线程内唯一,线程间可以不唯一。实际上,“进程唯一”就意味着线程内、线程间都唯一,这也是“进程唯一”和“线程唯一”的区别之处。“集群唯一”指的是进程内唯一、进程间也唯一。2.如何实现线程唯一的单例?我们通过一个HashMap来存储对象,其中key是线程ID,value是对象。这样我们就可以做到,不同的线程对应不同的对象,同一个线程只能对应一个对象。实际上,Java语原创 2020-08-13 22:57:09 · 104 阅读 · 0 评论 -
设计模式之美12-- 分层的优点, BO,entity,VO区分的好处
**为什么要分MVC三层开发?**我们刚刚提到,大部分业务系统的开发都可以分为三层:Contoller层、Service层、Repository层。为什么我们要分层开发?很多业务都比较简单,一层代码搞定所有的数据读取、业务逻辑、接口暴露不好吗?你可以把它作为一道面试题,试着自己思考下,然后再看我下面的讲解。对于这个问题,我总结了以下几点原因。**1.分层能起到代码复用的作用**同一个Repository可能会被多个Service来调用,同一个Service可能会被多个Controller调用。比如原创 2020-08-06 21:05:26 · 853 阅读 · 0 评论 -
设计模式之美11-- 对积分系统进行模块划分
第一种划分方式是:积分赚取渠道及兑换规则、消费渠道及兑换规则的管理和维护(增删改查),不划分到积分系统中,而是放到更上层的营销系统中。这样积分系统就会变得非常简单,只需要负责增加积分、减少积分、查询积分、查询积分明细等这几个工作。我举个例子解释一下。比如,用户通过下订单赚取积分。订单系统通过异步发送消息或者同步调用接口的方式,告知营销系统订单交易成功。营销系统根据拿到的订单信息,查询订单对应的积分兑换规则(兑换比例、有效期等),计算得到订单可兑换的积分数量,然后调用积分系统的接口给用户增加积分。第二.原创 2020-08-06 21:00:14 · 664 阅读 · 0 评论 -
设计模式之美10--迪米特法则
“高内聚、松耦合”是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。“高内聚”用来指导类本身的设计,“松耦合”用来指导类与类之间依赖关系的设计。所谓高内聚,就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一类中。相近的功能往往会被同时修改,放到同一个类中,修改会比较集中。所谓松耦合指的是,在代码中,类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动也不会或者很少导致依赖类的代码改动。迪米特法则:不该有直接依赖关系的类之间,不要原创 2020-08-02 12:17:31 · 97 阅读 · 0 评论 -
设计模式之美09--KISS原则
如何写出满足KISS原则的代码?不要使用同事可能不懂的技术来实现代码。比如前面例子中的正则表达式,还有一些编程语言中过于高级的语法等。不要重复造轮子,要善于使用已经有的工具类库。经验证明,自己去实现这些类库,出bug的概率会更高,维护的成本也比较高。不要过度优化。不要过度使用一些奇技淫巧(比如,位运算代替算术运算、复杂的条件语句代替if-else、使用一些过于底层的函数等)来优化代码,牺牲代码的可读性。KISS原则讲的是“如何做”的问题(尽量保持简单),而YAGNI原则说的是“要不要做”的问题原创 2020-08-02 12:11:56 · 199 阅读 · 0 评论 -
设计模式之美08--依赖注入,依赖倒置原则
通过依赖注入的方式来将依赖的类对象传递进来,这样就提高了代码的扩展性,我们可以灵活地替换依赖的类。1.控制反转实际上,控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。2.依赖注入依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过new的方式在类内部原创 2020-08-02 11:26:06 · 203 阅读 · 0 评论 -
设计模式之美08--接口隔离原则
客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。如何理解“接口隔离原则”?理解“接口隔离原则”的重点是理解其中的“接口”二字。这里有三种不同的理解。如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是某个类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。如果把“接口”理解为单个API接口或函数,部分调用者只需要函数中的部分功能,那我们就需要原创 2020-08-02 10:59:17 · 129 阅读 · 0 评论 -
设计模式之美07--里式替换原则
子类可以替换程序中任何地方的父类, 并且不影响原有的逻辑及正确性不被改变例如下面的代码, 虽然SecurityTransporter修改了sendRequest方法, 但是在使用时逻辑没变, 符合里式替换原则public class Transporter { private HttpClient httpClient; public Transporter(HttpClient httpClient) { this.httpClient = httpClient; } public Re原创 2020-08-02 10:21:16 · 113 阅读 · 0 评论 -
设计模式之美06--开闭原则
开闭原则: 对修改关闭, 对拓展开放1.如何理解“对扩展开放、对修改关闭”? 添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。关于定义,我们有两点要注意。第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。2.如何做到“对扩展开放、修改关闭”?我们要时刻具备扩展意识、原创 2020-08-02 10:07:20 · 126 阅读 · 0 评论 -
设计模式之美05--单一职责原则
单一职责原则一个类只负责一个功能或职责。 不要设计大而全的类, 要设计颗粒度小 , 功能单一的类。如何判断类的职责是否足够单一?不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:类中的代码行数、函数或者属性过多;类依赖的其他类过多,或者依赖类的其他类过多;私有方法过多;比较难给类起一个合适的名字;类中大量的方法都是集中操作类原创 2020-08-01 17:31:56 · 97 阅读 · 0 评论 -
设计模式之美04--设计一个鉴权服务; 防重攻击
设计一个鉴权服务;每个URL拼接上AppID、密码生成的token都是固定的。未认证系统截获URL、token和AppID之后,还是可以通过重放攻击的方式,伪装成认证系统,调用这个URL对应的接口。为了解决这个问题,我们可以进一步优化token生成算法,引入一个随机变量,让每次接口请求生成的token都不一样。我们可以选择时间戳作为随机变量。原来的token是对URL、AppID、密码三者进行加密生成的,**现在我们将URL、AppID、密码、时间戳四者进行加密来生成token。**调用方在进行接口原创 2020-08-01 16:44:51 · 308 阅读 · 0 评论 -
设计模式之美03--贫血模型和充血模式,领域驱动设计
1, 什么是基于贫血模型的传统开发模式?public class UserEntity {//省略其他属性、get/set/construct方法 private Long id; private String name; private String cellphone;}UserBo是一个纯粹的数据结构,只包含数据,不包含任何业务逻辑。业务逻辑集中在UserService中。我们通过UserService来操作UserBo。换句话说,Service层的数据和业务逻辑,被分割为BO和Serv原创 2020-08-01 11:57:05 · 310 阅读 · 0 评论 -
设计模式之类02--多用组合少用继承
为什么不推荐使用继承?比如鸟, 有会飞的,不会飞的. 会叫的,不会叫的,如果用继承, 类的继承层次会越来越深、继承关系会越来越复杂。一方面,会导致代码的可读性变差。因为我们要搞清楚某个类具有哪些方法、属性,必须阅读父类的代码、父类的父类的代码……一直追溯到最顶层父类的代码。另一方面,这也破坏了类的封装特性,将父类的实现细节暴露给了子类。子类的实现依赖父类的实现,两者高度耦合,一旦父类代码修改,就会影响所有子类的逻辑组合相比继承有哪些优势?实际上,我们可以利用组合(composition)、接原创 2020-08-01 11:36:36 · 165 阅读 · 0 评论 -
设计模式之美01---Java理论知识
1.滥用getter、setter方法在设计实现类的时候,除非真的需要,否则尽量不要给属性定义setter方法。除此之外,尽管getter方法相对setter方法要安全些,但是如果返回的是集合容器,那也要防范集合内部数据被修改的风险。2.Constants类、Utils类的设计问题对于这两种类的设计,我们尽量能做到职责单一,定义一些细化的小类,比如RedisConstants、FileUtils,而不是定义一个大而全的Constants类、Utils类。除此之外,如果能将这些类中的属性和方法..原创 2020-08-01 11:26:03 · 97 阅读 · 0 评论