如何通俗理解设计模式及其思想?

本文由玉刚说写做平台提供写做赞助html

原做者:却把清梅嗅java

版权声明:本文版权归微信公众号玉刚说全部,未经许可,不得以任何形式转载git

术与道

数据结构,算法,设计模式被认为是程序员必备技能的三叉戟,若是说编程语言的语法特性和业务编码能力是【术】,那么这三者能够称得上是【道】——【术】可让你在IT行业赖以生存,而【道】则决定你将来在技术这条道路上能够走多远。程序员

边学边忘的窘境

先自我介绍一下。github

我是一个两年工做经验的Android开发人员,就像不少同行同样,对于数据结构,算法,设计模式这些被奉为程序员必修的三门内功,几乎没有去系统性地学习过(曾经专业课的数据结构,现在也基本还给了老师)。面试

你问我想不想当一个称职的程序员,固然!数据结构,算法以及设计模式不止一次的被我列入学习计划中,我认为这是有意义而且必须的,而且,我也尝试在闲暇之余去主动学习它们。算法

可是很遗憾,至今为止,有关于数据结构和算法,我依然处于入门阶段,缘由就是:数据库

我学会没多久,一直没机会用到,而后就忘了!编程

若是您翻看过我以前的 相关博客 或者我 Github这个仓库,就能发现,我曾经关于数据结构和算法,都作出过尝试,可是遗憾的是,我并不能学以至用 ——它们匆匆而来,匆匆而去,就好像生命中的过客同样。设计模式

至于设计模式,由于空闲时间学习的时间并很少,虽然我也常常经过博客或者书籍学习设计模式,可是结果依然没有太大的改变:过于抽象的概念,加上不常用,让我很快把这些概念忘得差很少了。

我以为这种学习方式效率不是很高,因而我决定换一种学习的方式——经过阅读Github上那些开源库的源码,学习其中的设计思想和理念。

动机

和大多数人同样,我只是在编程行业众多平凡的开发者中的一员,在我职业生涯的伊始,我没有接触过技术大牛, 可是阅读源码可让我零距离碰撞全球行业最顶尖工程师们的思想,我认为对我而言这是一种效果不错的学习方式,让我受益不浅。

事实上,在要写这篇博客的时候,我依然忐忑不安,我担忧一篇文章若是写的不够好,会给读者带来误导。

我最终鼓起勇气写这篇文章的目的是:我想经过分享我的对于设计模式的理解,以及本身的学习方式和所得,这种学习方式可能并不是适用于全部人,可是它至少能给予须要的人一个参考

设计模式的分类

咱们先看设计模式的分类:

范围 建立型 结构型 行为型
Factory Method(工厂方法) Adapter(类) (适配器) Interpreter(解释器)
Template Method(模版方法)
对象 Abstract Factory(抽象工厂)
Builder(建造者)
Prototype(原型)
Singleton(单例)
Bridge(桥接)
Composite(组合)
Decorator(装饰者)
Façade(外观)
Flyweight(享元)
Proxy(代理)
Chain of Responsibility(职责链)
Command(命令)
Iterator(迭代器)
Mediator(中介者)
Memento(备忘录)
Observer(观察者)
State(状体)
Strategy(策略)
Visitor(访问者)

这是我从 这篇文章 中找到的对设计模式的概括。

同时,咱们须要了解到,设计模式的6个基本原则(这里先列出来,接下来会参考案例一个个解释):

  • 单一职责原则(Single Responsibility Principle)
  • 里氏代换原则(Liskov Substitution Principle)
  • 依赖倒转原则(Dependence Inversion Principle)
  • 接口隔离原则(Interface Segregation Principle)
  • 迪米特法则,又称最少知道原则(Demeter Principle)
  • 开闭原则(Open Close Principle)

在设计模式的学习过程当中,这些设计模式并不是是按照不一样类型按部就班讲解的,更多的场景是,多个不一样类型的设计模式相互组合——最终展现出来的是一个完整的架构设计体系。这种设计模式复杂组合带来的好处是:高内聚,低耦合,这使得库自己的拓展很是简单,同时也很是便于单元测试。

固然,对于经过源码,想一窥设计思想的学习者来讲,额外的接口,以及可能随之额来额外的代码会须要更多的学习成本,对于最初的我来讲,复杂的设计真的给我带来了很大的困扰,我试图去理解和反思这样设计的好处——它的确花费了我更多的时间,可是更让我受益不浅。

最初的收获——建立型模式

在Android学习的过程当中,我最早接触到的就是建立型模式,所谓建立型模式,天然与对象的建立有关。

实际上,不谈源码,实际开发中,咱们也遇到了不少建立型模式的体现,最多见的当属单例模式建造者模式(Builder)

1.“最简单”的设计模式

咱们以单例模式为例,他的定义是:

“一个类有且仅有一个实例,而且自行实例化向整个系统提供。”

相信你们对这个单例模式并不陌生,它被称为 “设计模式中最简单的形式之一”,它很简单,而且易于理解,开发者总能遇到须要持有惟一对象的业务需求。

以Android开发为例,常常须要在某个类中,使用到Application对象,它自己是惟一的,所以咱们只须要经过一个类持有它的静态引用,而后经过静态方法获取就能够了。

另外的一种需求是,某个类的对象会占用很大的内存,咱们也没有必要对这个类实例化两次,这样,保持其对象的类单例,可以省下更多的性能空间,好比Android的数据库db的引用。

实际上,单例模式的细分下来,有不少种实现方式,好比众所周知的懒汉式饿汉式Double CheckLock静态内部类枚举,这些不一样的单例实现方式,都有各自的优缺点(好比是否线程安全),也对应着不一样的适用场景,这也正是单例模式做为看起来“最简单”同时也是面试中的重点考察项目的缘由。

这些不一样的实现方式,百度上讲解的很是详细,本文不赘述。

咱们须要理解的是,咱们何时使用单例模式

对于系统中的某些类来讲,只有一个实例很重要,好比上述的Application,这很好理解,实际上,在开发过程当中,咱们更须要关注一些细节的实现。

好比对Gson的单例。

实际开发中,调用Gson对象进行转换的地方很是多,若是在调用的地方每次new Gson的话,是影响性能的。

Gson自己是线程安全的,它能够被多个线程同时使用,所以,我更倾向于经过下面的方式获取Gson的实例:

public class Gsons {

    private static class Holder {
        private static final Gson INSTANCE = new Gson();
    }

    public static Gson getInstance() {
        return Holder.INSTANCE;
    }
}
复制代码

不只是Gson, 除此以外还有好比网络请求的相关管理类(Retrofit对象,ServiceManager等),Android系统提供的各类XXXManager(NotificationManager)等等,这些经过单例的方式去管理它,可以让你业务设计的更加严谨。

2.Builder的链式调用

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。

Android开发者必定很熟悉它,由于咱们建立AlertDialog的时候,链式调用的API实在是赏心悦目:

new AlertDialog
   .Builder(this)
   .setTitle("标题")
   .setMessage("内容")
   .setNegativeButton("取消", new DialogInterface.OnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
            //...
       }
   })
   .setPositiveButton("肯定", new DialogInterface.OnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
            //....
       }
   })
   .create()
   .show();
复制代码

此外,稍微细心的同窗会发现,其实JDK中,StringBuilder和StringBuffer的源码中的append()方法也是Builder模式的体现:

public StringBuilder append(String str) {
        super.append(str);  // 调用基类的append方法
        return this;
}

// 基类的append方法
public AbstractStringBuilder append(String str) {
       if (str == null) str = "null";
       int len = str.length();
       ensureCapacityInternal(count + len);
       str.getChars(0, len, value, count);
       count += len;
       return this; // 返回构建对象
}
复制代码

除了赏心悦目的代码以外,我更关注Builder模式的使用场景:

当咱们面临着一个复杂对象的建立工做,其一般由各个部分的子对象用必定的算法构成;因为需求的变化,这个复杂对象的各个部分常常面临着剧烈的变化,可是将它们组合在一块儿的算法却相对稳定。

很好,我把 这个学习网站 关于Builder模式的适用场景复制下了下来,我曾经在学习它的时候尝试去理解它的叙述,所得出的结论是 ——上文的定义很是严谨,可是我看不懂。

咱们参考AlertDialog,对于一个Dialog而言,它的基本构成是复杂的(有标题,内容,按钮及其对应的事件等等属性),可是在实际需求中,不一样的界面,咱们须要展现给用户的Dialog是不同的(标题不同,内容不同,点击事件也不同),这些各个部分都是在不断剧烈的变化,可是他们组合起来是相对稳定的(就是一个Dialog弹出展现在界面上)。

在这种状况下,咱们能够尝试使用Builder模式,和普通的构造器生成对象不一样,若是没有需求,咱们能够忽略配置某些属性——对于Dialog,我能够不去定义title,也能够不去定义取消按钮的点击事件,他们内部都有默认的处理;此外,对于API的设计来说,Builder模式更利于去扩展新的功能或者属性。

Builder模式在咱们开发中很是常见,除上述案例以外,Android流行的图片加载库,以及Notification通知的实例化等等,都能看到Builder的身影。

上文说到,Builder模式对于对象的建立提供了很是赏心悦目的API,我理解了Builder模式的思想和实现方式以后,便尝试给本身的一些工具类加一些这样的设计。

很快,我遇到了一个问题,那就是——这样写太TM累了!

3.避免过分设计

关于过分设计的定义,请参考 什么是软件开发中的过分设计? 的解释,我认为讲解的很是风趣且易懂。

从我我的的角度而言,我遇到了问题,我尝试给一些工具改成Builder实现,结果是,我添加了不少不少代码,可是效果平平。

不只如此,这样的设计给个人工具带来了更多的复杂度,原本一个构造器new一下能解决的问题,非要不少行代码链式配置,这种设计,作了还不如不作。

这样的结果,让我对网络上一位前辈的总结很是赞同,那就是:

设计模式的一个重要的做用是代码复用,最终的目的是提高效率。 因此,一个模式是否适合或必要,只要看看它是否能减小咱们的工做,提高咱们的工做效率

那么,如何避免过分设计,个人经验告诉我,写代码以前多思考,考虑不一样实现方式所需的成本,保证代码的不断迭代和调整

即便如此,在开发的过程当中,过分设计仍然是难以免的状况,只有依靠经验的积累和不断的总结思考,慢慢调整和丰富本身的我的经验了。

4. 单一职责原则与依赖注入

对于单例模式,我彷佛也会遇到过分设计这种状况——每一个对象的单例都须要再写一个类去封装,彷佛也太麻烦了。

实际上这并不是过分设计,由于这种设计是必要的,它可以节省性能的开销,可是对象的建立和管理依然是对开发者一个不可小觑的工做量。

此外,还须要考量的是,对于一个复杂的单例对象,它可能有不少的状态和依赖,这意味着,单例类的职责颇有可能很,这在必定程度上违背了单一职责原则

一个类只负责一个功能领域中的相应职责,或者能够定义为:就一个类而言,应该只有一个引发它变化的缘由。

单一职责原则告诉咱们:一个类不能太“累”! 一个类的职责越(这每每从构造器所须要的依赖就能体现出来),它被复用的可能性就越小。

在了解了单例模式的优势和缺点后,咱们能够有选择的使用单例模式,对于依赖过于复杂的对象的单例,咱们更须要仔细考量。

对于复杂的依赖管理,依赖注入库(好比Dagger)是一个能够考虑的解决方案(慎重),对于单例模式的实现,你只须要在Module中对应的依赖Provider上添加一个@Singleton注解,编译器会在编译期间为您自动生成对应的单例模式代码。

不可否认,这个工具须要相对较高的学习成本,可是学会了依赖注入工具并理解了IOC(控制反转)和DI(依赖注入)的思想以后,它将成为你开发过程当中无往不胜的利器。

5.开闭原则

开闭原则:一个软件应对扩展开放、对修改关闭,用head first中的话说就是:代码应该如晚霞中 的莲花同样关闭(免于改变),如晨曦中的莲花同样开放(可以扩展).

建造者模式(Builder)即是开闭原则的彻底体现,它将对象的构建调用隔离开来,不一样的使用者均可以经过自由的构建对象,而后使用它。

6.小结

建立型模式是最容易入门的,由于该类型的模式,更常常暴露在开发者面前,可是它们并不简单,咱们除了知道这些模式的使用方式,更应该去思考何时用,用哪一个,甚至是组合使用它们——它们有些互斥,有些也能够互补,这须要咱们去研究更经典的一些代码,并本身做出尝试。

不仅是建立型,接下来的结构型和行为型的设计模式,本文也不会去一一阐述其目录下全部的设计模式。

结构型模式

1.定义

首先阐述书中结构型模式的定义:

结构型模式涉及到如何组合类和对象以得到更大的结构。结构型类模式采用继承机制来组合接口或实现。

在学习之初,对我我的而言,阅读《设计模式:可复用面向对象软件的基础》 的内容宛如诵读天书,书中对每种设计模式都进行了详细的讲解,可是我看完以后,很快就忘掉了,亦或是对看起来很是类似的两种设计模式感到疑惑——书中的讲解细致入微,可是太抽象了。

最终(也就是如今),我我的对于结构型模式的理解是,经过将不一样类或对象的组合,采用继承或者组合接口,或者组合一些对象,以实现新的功能

用一句话陈述,就是对不一样职责的对象(以对象/抽象类/接口的形式)之间组合调度的实现方式。

2.并不是全部对象的组合都是结构型模式

实际上,并不是全部对对象的组合都属于结构型模式,构型模式的意义在于,对一些对象的组合,以实现新功能的方式—— 经过运行时,经过改变组合的关系,这种灵活性产生不一样的效果,这种机制,普通的对象组合是不可能实现的。

接下来我将经过阐述数种不一样的结构型模式在实际开发中的应用,逐步加深对上文叙述的理解。

3.RecyclerView:适配器模式

RecyclerView是Android平常开发中实现列表的首选方案,站在个人角度来看,我还没想明白一个问题,RecyclerView是如何实现列表的?

我能够回答说,经过实现RecyclerView.Adapter就能实现列表呀!

事实上,是这样的,可是这引起了另一个问题,Adapter和RecyclerView之间的关系是什么,为啥实现了Adapter就能实现RecyclerView呢?

思考现实中的一个问题,我有一台笔记本电脑,个人屋子里也有一个电源,我如何给个人笔记本充电?

不假思索,咱们用笔记本的充电器链接电源和笔记本就好了,实际上,充电器更官方的叫法应该叫作电源适配器(Adapter)。对于笔记本电脑和电源来说,它们并无直接的关系,可是经过Adapter适配器,它们就能产生新的功能——电源给笔记本充电。

RecyclerView和数据的展现也是同样,数据对象和RecyclerView并无直接的关系,可是我若是想要将数据展现在RecyclerView上,经过给RecyclerView配置一个适配器(Adapter)以链接数据源,就能够了。

如今咱们来看Adapter模式的定义:

使本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。

如今咱们理解了适配器模式的应用场景,可是我想抛出一个问题:

为啥我要实现一个Adapter,设计之初,为何不能直接设置RecyclerView呢?

好比说,我既然有了数据源,为何设计之初,不能让RecyclerView经过这样直接配置呢:

mRecyclerView.setDataAndShow(datas);
复制代码

个人理解是,若是把RecyclerView比喻为屋子里的电源插口,电源不知道它将要链接什么设备(一样,RecyclerView也不可能知道它要展现什么样的数据,怎么展现),而不一样的设备的接口也可能不同,可是只要为设备配置一个对应的适配器,两个不相关的接口就能一块儿工做。

RecyclerView的设计者将实现对开发者隐藏,并经过Adapter对开发者暴露其接口,开发者经过配置数据源(设备)和对应的适配器(充电器),就能实现列表的展现(充电)。

4.Retrofit:外观模式与动态代理

说到迪米特法则(也叫最少知识原则),这个应该很好理解,就是下降各模块之间的耦合:

迪米特法则:一个软件实体应当尽量少地与其余实体发生做用。

个人学习过程当中,让我感觉到设计模式的组合之美的第一个库就是Retrofit,对于网络请求,你只须要配置一个接口:

public interface BlogService {

    @GET("blog/{id}")
    Call<ResponseBody> getBlog(@Path("id") int id);
}

// 使用方式
// 1.初始化配置Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://localhost:4567/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
// 2.实例化BlogService接口 
BlogService service = retrofit.create(BlogService.class);
复制代码

Retrofit的源码中,经过组合,将各类设计模式应用在一块儿,构成了整个框架,保证了咱们常说的高内聚,低耦合,堪称设计模式学习案例的典范,以下图(图片参考感谢这篇文章):

在分析整个框架的时候,咱们首先从API的使用方式入手,咱们能够看到,在配置Retrofit的时候,库采用了外观模式做为Retrofit的门面。

有朋友说了,在我看来,Retrofit的初始化,不该该是Builder模式吗,为何你说它是外观模式呢?

咱们首先看一下《设计模式:可复用面向对象软件的基础》一书对于外观模式的定义:

为子系统中的一组接口提供一个一致的界面,外观模式定义一个高层接口,这个接口使得这一子系统更容易使用。

个人解读是,对于网络请求库的Retrofit,它内部有着不少不一样的组件,包括数据的序列化,线程的调度,不一样的适配器等,这一系列复杂的子系统,对于网络请求来说,都是不可或缺的且关系复杂的,那么,经过将它们都交给Retrofit对象配置调度(固然,Retrofit对象的建立是经过Builder模式实现的),对于API的调用者来讲,使用配置起来简单方便,这符合外观模式 的定义。

简单理解了外观模式的思想,接下来咱们来看一下动态代理,对于最初接触Retrofit的我来讲,我最难以理解的是我只配置了一个接口,Retrofit是如何帮我把Service对象建立出来的呢?

// 2.实例化BlogService接口 
BlogService service = retrofit.create(BlogService.class);
复制代码

实际上,并无BlogService这个对象的建立,service只不过是在jvm运行时动态生成的一个proxy对象,这个proxy对象的意义是:

为其余对象提供一种代理以控制对这个对象的访问。

我想经过BlogService进行网络请求,Retrofit就会经过动态代理实现一个proxy对象代理BlogService的行为,当我调用它的某个方法请求网络时,其实是这个proxy对象经过解析你的注解方法的参数,经过一系列的逻辑包装成一个网络请求的OkHttpCall对象,并请求网络。

如今我明白了,怪不得我不管怎么给Service的接口和方法命名,Retrofit都会动态生成代理对象并在调用其方法时进行解析,对于复杂多变的网络请求来说,这种实现的方式很是合适。

5.里氏替换原则

在优秀的源码中,咱们常常能够看到,不少功能的实现,都是依赖其接口进行的,这里咱们首先要理解面向对象中最重要的基本原则之一里氏替换原则

任何基类能够出现的地方,子类必定能够出现。

里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,因此里氏代换原则是对实现抽象化的具体步骤的规范。

向上转型是Java的基础,咱们常常也用到,实际上,在进行设计的时候,尽可能从抽象类继承,而不是从具体类继承。同时,保证在软件系统中,把父类都替换成它的子类,程序的行为没有变化,就足够了。

6.小结

经过上述案例,咱们简单理解了几种结构型设计模式的概念和思想,总结一下:

在解决了对象的建立问题以后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,由于如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。因此也有多种结构型模式可供开发人员选择使用。

提升类之间的协做效率——行为型模式

1.定义

咱们先看书中对行为型模式比较严谨的定义:

行为模式涉及到算法和对象间职责的分配,行为模式不只描述对象或类的模式,还描述它们之间的通讯模式。这些模式刻划了在运行时难以跟踪的复杂的控制流,将你的注意力从控制流转移到对象间的联系方式上来。

依然是有点难以理解,咱们先举两个例子:

2.OkHttp:Intercepter和职责链模式

Okhttp 中, Intercepter就是典型的职责链模式的体现.它能够设置任意数量的Intercepter来对网络请求及其响应作任何中间处理——设置缓存, Https的证书验证, 统一对请求加密/防串改, 打印自定义Log, 过滤请求等。

new OkHttpClient.Builder()
              .addNetworkInterceptor(interceptor1)
              .addNetworkInterceptor(interceptor2)
              .addNetworkInterceptor(interceptor3)
复制代码

职责链模式的定义为:

让多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将他们连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

以现实为例,职责链模式之一就是网络链接,七层或五层的网络链接模型以下:

  • 网络请求发出,通过应用层->传输层->网络层->链接层->物理层

  • 收到响应后,物理层->链接层->网络层->传输层->应用层

在请求通过各层时,由每层轮流处理.每层均可以对请求或响应进行处理.并能够中断连接,以自身为终点返回响应。

3.RxJava:观察者模式

Android开发中,点击事件的监听是很经典观察者模式的体现:

button.setOnClickListener(v -> {
    // do something
})
复制代码

对设置OnClickListener来讲,View是被观察者,OnClickListener是观察者,二者经过setOnClickListener()方法达成注册(订阅)关系。订阅以后,当用户点击按钮,View就会将点击事件发送给已经注册的 OnClickListener。

一样,对于能够和Retrofit配套的RxJava来说,它是也经过观察者模式来实现的。

// 被观察者
Observable observable = Observable
                          .just("Hello", "Hi", "Aloha")

// 观察者
Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

// 执行订阅关系
observable.subscribe(observer);
复制代码

RxJava强大的异步处理,将数据的建立接收分红了两部分,对于观察者来讲,它不关心数据何时发射的,怎么发射的,它只关心,当观察到到最新数据时,怎样进行对应的处理。

咱们知道了观察者模式的这种方式,咱们更须要去深刻思考对于观察者模式使用先后,对咱们代码设计系统的影响——它的好处是什么?

最直接的好处是,被观察者并不知道观察者的详细实现

就像我刚才所说的,被观察者只负责发射事件,对于事件如何处理,它并不关心,这意味着被观察者观察者之间并非紧密耦合的,它们能够处于一个系统中的不一样抽象层次。

不一样抽象层次这句话自己就有点抽象,咱们以Button的点击事件为例,对于Button来说,它是一个库的工具,它应该属于项目中底层组件,而对于咱们某个Activity的某个点击事件来说,它是属于靠顶部业务层的代码,能够说,Button和点击事件是不在一个抽象层次较低层次的Button能够将点击事件发送给较高层次的事件监听器并通知它。

而若是不采用这种方式,观察者和被观察者就必须混在一块儿,这样对象就会横贯项目的2个层次(违反了层次性),或者必须放在这两层中的某一层中(可能会损害层次抽象)。

底层组件按钮被点击后行为,抽象出来交给较高层级去实现,了解了这种方式的好处,依赖倒置原则就不难理解了。

4.依赖倒置原则

如今咱们来了解一下依赖倒置原则

抽象不该该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而非针对实现编程。

它的原则是:

  • 1.高层模块不该该依赖于低层模块,两个都应该依赖于抽象。
  • 2.抽象不该该依赖细节,细节应该依赖于抽象。

在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范,而不去涉及任何具体的操做,把展示细节的任务交给他们的实现类去完成。

了解了依赖倒置原则,咱们再接再砺,学习最后一个设计模式的基本原则:

5.接口隔离原则

接口隔离原则:客户端不该该依赖它不须要的接口;一个类对另外一个类的依赖应该创建在最小的接口上。

这个应该是最好理解的原则了,它的意义就是:使用多个专门的接口比使用单一的总接口要好

这很好理解,对于鸟的实现(Bird),咱们能够定义两个功能接口,分别是Fly和Eat,咱们可让Bird分别实现这两个接口——若是咱们还有一个Dog,那么对于Eat接口,能够复用,可是若是只有一个接口(包含Fly和Eat两个功能),对于Dog来讲,它是不会飞(Fly)的,那么就须要针对Dog再声明一个新的接口,这是没有必要的设计。

6.小结

在对象的结构和对象的建立问题都解决了以后,就剩下对象的行为问题了,若是对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协做效率就会提升。

如今咱们再看上文中对行为型模式比较严谨的定义,相信你们可以理解一些了:

行为模式涉及到算法和对象间职责的分配,行为模式不只描述对象或类的模式,还描述它们之间的通讯模式。这些模式刻划了在运行时难以跟踪的复杂的控制流,将你的注意力从控制流转移到对象间的联系方式上来。

喘口气

关于设计模式相关的讲解内容,到此基本就告一段落了。

等等...

我一个设计模式都没学会,你TM告诉我你讲完了?

一无所得?

本文并无去经过代码简单描述各个设计模式的实现方式,于我而言毫无心义,设计思想是经过不断思考,理解并在亲身尝试中学会的,短期快速大量阅读学习的方式效果甚微,即便学会了,如何将sample中的设计思想,转换为实际产品中复杂的业务设计,这也是一个很是大的难题。

在这里,我引用《倚天屠龙记》中我最喜欢的经典片断, 就是张三丰在武当山当着敌人的面教张无忌太极剑那段。

只听张三丰问道:‘孩儿,你看清楚了没有?’张无忌道:‘看清楚了。’张三丰道: ‘都记得了没有?’张无忌道:‘已忘记了一小半。’张三丰道:‘好,那也难为了你。你本身去想一想罢。’张无忌低头默想。过了一会,张三丰问道:‘现下怎样了?’张无忌道: ‘已忘记了一大半。’

周颠失声叫道:‘糟糕!愈来愈忘记得多了。张真人,你这路剑法非常深奥,看一遍怎能记得?请你再使一遍给咱们教主瞧瞧罢。’

张三丰微笑道:‘好,我再使一遍。’提剑出招,演将起来。众人只看了数招,心下大奇,原来第二次所使,和第一次使的居然没一招相同。周颠叫道:‘糟糕,糟糕!这可更加叫人胡涂啦。’张三丰画剑成圈,问道:‘孩儿,怎样啦?’张无忌道:‘还有三招没忘记。’张三丰点点头,收剑归座。

张无忌在殿上缓缓踱了一个圈子,沉思半晌,又缓缓踱了半个圈子,抬起头来,满脸喜色,叫道:‘这我可全忘了,忘得干干净净的了。’张三丰道:‘不坏不坏!忘得真快,你这就请八臂神剑指教罢!’

总结

关于设计模式,个人理解是,不要拘泥于其概念,只有深入理解了其设计的思想,理解以后,亲自去尝试使用它,在使用的过程当中加深对这种思想的理解,我想比经过书籍或者博客一个一个的去学,效果要更好。

我学习它们的方式是,学习一些优秀开源库的源码,思考为何这里使用这些设计模式,以后再参考《设计模式》一书的相关概念,最后本身去尝试并加深理解。

于我而言,这种方式的短板在于刚开始的时候,可能须要更多的时间去学习,不少库的源码在初接触时,并不是容易理解,可是好处是,当学会以后,这种思想就很难再从你的记忆中跑掉了,并且,在写代码时,会下意识尝试使用这些模式(固然,更多状况是打开2个窗口,一边参考源码,一边学习将其融入到本身的代码中)。

设计模式相对于分类和概念正如太极拳(剑),它更是一种思想,一种应对变化的解决思想——我不认为本文本身的学习方式和心得,可以适合每个正在阅读本文的读者,可是若是本文对您对技术成长的道路上有一些帮助,对我而言这就是值得的。

参考

1.菜鸟教程——设计模式:
http://www.runoob.com/design-pattern/design-pattern-tutorial.html

2.《设计模式:可复用面向对象软件的基础》
伽玛等著;李英军等译,机械工业出版社,2015年12月初版37次印刷

3.Retrofit分析-漂亮的解耦套路: https://blog.piasy.com/2016/06/25/Understand-Retrofit/

4.建立型模式、结构型模式和行为型模式之间的关系 https://blog.csdn.net/qq_34583891/article/details/70853637

欢迎关注个人微信公众号,接收第一手技术干货
相关文章
相关标签/搜索