LieBrother

当才华撑不起野心时,应该静下心来学习;当能力驾驭不了目标时,应该沉下心来历练。


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

设计模式看了又忘,忘了又看?

发表于 2019-05-29   |     |   阅读次数

文章首发:设计模式看了又忘,忘了又看?

LieBrotherpdf

LieBrotherpdf

设计模式收藏这篇就够了

耗时了 5 个月,终于把设计模式一整个系列写完。其实设计模式这一系列文章网上已经有很多非常好、非常优秀的文章,为什么要写呢?

一方面是为了学得更扎实,印象中设计模式学习了 2 遍,记得牢的基本就那几个众所周知的,反思前面 2 次学习过程,缺少了思考的过程,没有把知识消化掉转化成自己的,就像动物一样,吃进去的东西没有消化只能排出。

另一方面是利用这个学习过程,学会把知识用文字表达出来,也把这份知识分享给各位同道中人。

没有期望说这系列的每篇文章都对你有意义,这要求太高了,我远没有这个能力,但是如果能有一篇文章让你看完就把这个设计模式都记住了,那这系列文章的目标就达到了。

这里整理了这个系列文章汇总,有关注公众号的同学可以直接点击菜单【设计模式】看所有文章,没有关注的同学可以收藏这篇汇总文章。

划重点:这一系列文章已经整理成 PDF 电子版,在公众号 LieBrother 后台回复【设计模式】即可获取。

通过下面链接获取试读版。

一故事一设计模式-LieBrother(试读版).pdf【提取码:3f65】

六大原则

单一职责原则(方法:修改名字还是密码?接口:洗碗、买菜还是倒垃圾?类:注册、登录和注销)
里氏替换原则(我儿来自新东方烹饪)
依赖倒置原则(抠门的饭店老板)
接口隔离原则(小伙子的作坊)
迪米特法则(手机上看电子书)
开闭原则(社保这点事)

五大创建型模式

创建型模式:单例模式(小明就只有 1 辆车)
创建型模式:工厂方法(小明家的车库)
创建型模式:抽象工厂(宝马车就得用宝马轮胎和宝马方向盘)
创建型模式:建造者模式(汤这么煲)
创建型模式:原型模式(复印书籍)

十一大行为型模式

行为型模式:模板方法(运动鞋制造过程)
行为型模式:中介者模式(租房找中介)
行为型模式:命令模式(技术经理分配任务)
行为型模式:责任链模式(面试过五关斩六将)
行为型模式:策略模式(洗衣模式)
行为型模式:迭代器模式(听歌这件事)
行为型模式:观察者模式(朋友圈)
行为型模式:状态模式(P2P借款状态流程)
行为型模式:备忘录模式(你的发布平台好用么?)
行为型模式:解释器模式(SQL 解析)
行为型模式:访问者模式(宴请领导人)

七大结构型模式

结构型模式:适配器模式(你用过港式插座转换器么?)
结构型模式:桥接模式(IOS、Android 二分天下)
结构型模式:组合模式(程序猿组织架构)
结构型模式:装饰模式(夏天到了,吃碗龟苓膏解解暑)
结构型模式:外观模式(你需要一个技术组长)
结构型模式:享元模式(还记得童年的蜡笔画么?)
结构型模式:代理模式(你我都知道的这道墙)

希望文章对您有帮助!

LieBrother

结构型模式:代理模式

发表于 2019-05-15   |     |   阅读次数

文章首发:
结构型模式:代理模式

七大结构型模式之七:代理模式。

简介

姓名 :代理模式

英文名 :Proxy Pattern

价值观 :为生活加点料

个人介绍 :
Provide a surrogate or placeholder for another object to control access to it.
为其他对象提供一种代理以控制对这个对象的访问。
(来自《设计模式之禅》)

你要的故事

咱们从事 IT 行业,随时都可能上网查东西,如果网络速度慢或者网络访问受限制,那是相当的折磨,忍无可忍。而咱在国内网络比较特殊,有个墙围着,俗称防火长城。今天讲到代理模式,就来讲讲这道墙。这墙是这么实现的,我们上网,正常的网络是世界各地的网站我们都能访问,而加上这道墙,相当于在我们上网的时候做了一层代理,这一层代理把禁用的网站给过滤掉,使得我们没法访问被禁用的网站。下面通过代码来讲解。

定义一个互联网接口,里面有一个访问网站的通用方法 access。

1
2
3
4
5
6
7
8
/**
* 互联网
*/
interface Internet {

String access(String domain);

}

定义世界范围内的网络类,可以访问任何存在的网站。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 世界网络
*/
class WorldNetwork implements Internet {

@Override
public String access(String domain) {
System.out.println("访问网站:" + domain);
return domain + "网站内容";
}

}

定义中国的网络类,就是代理类,实现墙的功能。disable 对象存储了在国内禁止访问的网站,用户在访问网站时(也就是调用 access 访问)先判断网站是不是在禁用的网站集合里面,如果是则禁用,如果不是则继续访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 中国网络(就是代理)
*/
class ChinnessNetwork implements Internet {

private Set<String> disable;

private Internet internet;

public ChinnessNetwork(Internet internet) {
this.internet = internet;
this.disable = new HashSet<>();
this.disable.add("www.google.com");
this.disable.add("www.facebook.com");
}

@Override
public String access(String domain) {
if (disable.contains(domain)) {
System.out.println("禁止访问该网站:" + domain);
return "禁止访问该网站:" + domain;
}
return internet.access(domain);
}
}

测试代码,ChinnessNetwork 作为代理类,WorldNetwork 作为被代理类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ProxyTest {

public static void main(String[] args) {
WorldNetwork worldNetwork = new WorldNetwork();
ChinnessNetwork chinnessNetwork = new ChinnessNetwork(worldNetwork);
chinnessNetwork.access("www.google.com");
chinnessNetwork.access("www.baidu.com");
}

}

打印结果:
禁止访问该网站:www.google.com
访问网站:www.baidu.com

看到结果,万能的 google 被屏蔽在外,我们只能默默用 baidu。

总结

代理模式简单说就是在原来对象的功能基础上加上额外的功能,在工作开发中这个很好用,比如我们要统计系统中各方法执行的时间,就可以用代理模式来实现。开源框架中也用得很多,比如 Spring 的 AOP 等等。

上面简单的分享了代理模式,也是最简单的一个代理模式,名称叫静态代理。在开发中用的最多的是动态代理,基于这篇文章主要讲述设计模式的基础内容,后面找个机会再分享动态代理的内容。

好了,6 篇原则 + 23 篇设计模式已经完结了。所有的文章都整理在『设计模式』菜单里面,如下图所示,方便大家忘记了可以再瞄一眼。后面准备把这 29 篇文章整理成 PDF 分享给大家。

设计模式系列

推荐阅读

结构型模式:装饰模式

结构型模式:外观模式

结构型模式:享元模式

公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
加个人微信备注『教程』获取架构师、机器学习等教程

LieBrother

结构型模式:享元模式

发表于 2019-05-07   |     |   阅读次数

文章首发:
结构型模式:享元模式

热气球

七大结构型模式之六:享元模式。

简介

姓名 :享元模式

英文名 :Flyweight Pattern

价值观 :共享富贵

个人介绍 :
Use sharing to support large numbers of fine-grained objects efficiently.
使用共享对象可有效地支持大量的细粒度的对象。
(来自《设计模式之禅》)

你要的故事

还记得笔袋么?可能有人已经忘记了,在写这篇文章之前其实我也忘了,从初中开始就再也没用过笔袋。拿笔袋来讲享元模式再适合不过了。笔袋放各种各样的笔,今天我们不讲别的,就讲蜡笔。前段时间在逛公园的时候,看到一位老师在画画,画的就是蜡笔画,第一次看到真正的蜡笔画,真的很震撼,原来蜡笔也可以把景色画得那么美。当时偷偷拍了一张,看下图。

我们就拿这幅画来说,里面画了草、树、路、山、天空等等。如果没有用享元模式,我们可能这样子实现。

蜡笔接口。

1
2
3
4
5
interface ICrayon {

void draw(String place);

}

蜡笔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 蜡笔
*/
class Crayon implements ICrayon {

private String color;

public Crayon(String color) {
System.out.println("---新建【" + color + "】蜡笔" );
this.color = color;
}

@Override
public void draw(String place) {
System.out.println("用" + this.color + "蜡笔画" + place);
}
}

测试代码。这幅画是小明和小红一起画,小明画了草和路,小红画了树和蓝天。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class NoFlyweightTest {

public static void main(String[] args) {
drawByXiaoMing();
drawByXiaoHong();
}

public static void drawByXiaoMing() {
ICrayon greenCrayon = new Crayon("绿色");
greenCrayon.draw("草");

ICrayon grayCrayon = new Crayon("灰色");
grayCrayon.draw("路");
}

public static void drawByXiaoHong() {
ICrayon blueCrayon = new Crayon("蓝色");
blueCrayon.draw("蓝天");

ICrayon greenCrayon = new Crayon("绿色");
greenCrayon.draw("树");
}

}

打印结果:
---新建【绿色】蜡笔
用绿色蜡笔画草
---新建【灰色】蜡笔
用灰色蜡笔画路
---新建【蓝色】蜡笔
用蓝色蜡笔画蓝天
---新建【绿色】蜡笔
用绿色蜡笔画树

我们发现小明和小红都用了绿色蜡笔,而这里新建了 2 次绿色蜡笔,也就是在整个作画过程中,小明和小红并不是共用一套蜡笔,而是各自用一套蜡笔,在现实中是没什么问题的,但是在软件开发中,如果这种情况出现,其实相当于资源浪费,因为每个蜡笔都会占用内存,可以共用的我们尽量共用,节省一些内存空间,特别是出现很多这种可以共享却没有共享的对象时候。下面我们引入享元模式。享元模式实现方法相当于我们蜡笔都放在了笔袋,小明和小红用完就放到笔袋里面,每一种颜色的蜡笔只有一根,也就是他们共用一套蜡笔。代码如下所示。

笔袋代码。我们用了 Map 作为容器,如果容器里面没有想要颜色的蜡笔,则创建新的蜡笔,并存到容器里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 笔袋
*/
class CrayonFactory {

private static Map<String, ICrayon> data = new HashMap<>();

public static ICrayon getCrayon(String color) {
if (data.containsKey(color)) {
return data.get(color);
}
ICrayon crayon = new Crayon(color);
data.put(color, crayon);
return crayon;
}

}

测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class FlyweightTest {

public static void main(String[] args) {
drawByXiaoMing();
drawByXiaoHong();
}

public static void drawByXiaoMing() {
ICrayon greenCrayon = CrayonFactory.getCrayon("绿色");
greenCrayon.draw("草");

ICrayon grayCrayon = CrayonFactory.getCrayon("灰色");
grayCrayon.draw("路");
}

public static void drawByXiaoHong() {
ICrayon blueCrayon = CrayonFactory.getCrayon("蓝色");
blueCrayon.draw("蓝天");

ICrayon greenCrayon = CrayonFactory.getCrayon("绿色");
greenCrayon.draw("树");
}
}

打印结果:
---新建【绿色】蜡笔
用绿色蜡笔画草
---新建【灰色】蜡笔
用灰色蜡笔画路
---新建【蓝色】蜡笔
用蓝色蜡笔画蓝天
用绿色蜡笔画树

利用享元模式实现的结果,小红画树所用到的绿色蜡笔跟小明画草的绿色蜡笔一样,小红用到时并没有新建绿色蜡笔。

总结

是不是有一种,原来这就是享元模式的感觉?平时开发过程中经常见到这种因为很多重复的对象,所以利用享元模式来实现的场景。享元模式合理提高了对象的复用性,减少了程序的内存占用,还有一个提高性能的地方就是减少了对象创建的过程。好了,收下这个简单的设计模式。欢迎关注公众号,一起学习进步。

推荐阅读

结构型模式:外观模式

结构型模式:装饰模式

结构型模式:组合模式

公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
加个人微信备注『教程』获取架构师、机器学习等教程

LieBrother

结构型模式:外观模式

发表于 2019-05-05   |     |   阅读次数

文章首发:
结构型模式:外观模式

花

七大结构型模式之五:外观模式。

简介

姓名 :外观模式

英文名 :Facade Pattern

价值观 :统一口径、一致对外

个人介绍 :
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
(来自《设计模式之禅》)

你要的故事

作为开发同学,我们平时打交道最多的就是需求同学和测试同学,公司小的时候,什么事情都全靠吼,工作也直接一对一,一个需求下来,需求同学先跟开发同学一起跟进这个需求,需求开发完成了,需求同学和测试同学沟通了需求的测试要点,测试同学就开测。这个过程中需求一直跟到上线。我们用代码来描述这个过程。

开发同学,负责开发需求。

1
2
3
4
5
6
7
8
9
10
/**
* 开发同学
*/
class Developer {

public void develop(String name) {
System.out.println("开发需求:" + name);
}

}

测试同学,负责测试需求。

1
2
3
4
5
6
7
8
9
10
/**
* 测试同学
*/
class Tester {

public void test(String name) {
System.out.println("测试需求:" + name);
}

}

需求同学,负责提需求,也负责跟进需求的开发、测试,直到上线。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 需求同学
*/
class Demander {

private Developer developer = new Developer();
private Tester tester = new Tester();

public void demand(String name) {
System.out.println("提需求:" + name);
developer.develop(name);
tester.test(name);
}

}

测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
public class FacadeTest {

public static void main(String[] args) {
Demander demander = new Demander();
demander.demand("开发一个跟淘宝一样的系统");
}
}

打印结果:
提需求:开发一个跟淘宝一样的系统
开发需求:开发一个跟淘宝一样的系统
测试需求:开发一个跟淘宝一样的系统

公司小的时候,这样干没啥问题,咱关注的是业务的迭代速度和沟通成本,大家都是在一块办公,随时吼一声完事。当公司发展到一定程度,比如有 100 来人,其中需求 10 人、开发 70 人、测试 20 人,那就没法靠吼来沟通了,需要有一个比较规范化的沟通机制。一般会这样子引进,开发会把一些沟通能力较强、把控开发流程能力较好的同学升职为组长,负责保证一个需求的正常开发,他们会直接面对需求同学,直接沟通需求的开发要点,然后组长安排开发同学和测试同学跟进这个需求直到上线,也就是把需求同学以前的工作分配到开发组长,让他把控整个流程,这样就不会使得开发同学、测试同学、需求同学之间互相频繁沟通影响效率。这样子我们看看代码实现。

多了一个技术组长的类,负责跟进整个需求的开发测试过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 技术组长
*/
class Leader {

private Developer developer = new Developer();
private Tester tester = new Tester();

public void processDemand(String name) {
developer.develop(name);
tester.test(name);
}

}

需求同学就不用直接和开发同学、测试同学沟通了,就跟技术组长对接就好。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 需求同学
*/
class Demander2 {

public Leader leader = new Leader();
public void demand(String name) {
System.out.println("提需求:" + name);
leader.processDemand(name);
}

}

测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FacadeTest {

public static void main(String[] args) {
Demander2 demander2 = new Demander2();
demander2.demand("开发一个跟微信一样的系统");
}

}

打印结果:
提需求:开发一个跟微信一样的系统
开发需求:开发一个跟微信一样的系统
测试需求:开发一个跟微信一样的系统

这个就是我们的外观模式,我们的技术组长就是外观模式的象征,他专门对外提供接收需求服务,然后安排需求给开发同学和测试同学,保证完成。

总结

外观模式通过一个对外统一的接口,隐藏了内部的具体实现,使得外部系统可以更加简单的访问,也减少了外部系统对内部系统的依赖,从上面的例子讲,如果开发同学开发一半生病短时间无法来上班,交接给其他同学,由组长内部安排解决,需求同学并不需要知道。外观模式在微服务交互之间经常使用。

推荐阅读

结构型模式:桥接模式

结构型模式:组合模式

结构型模式:装饰模式

公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
加个人微信备注『教程』获取架构师、机器学习等教程

LieBrother

结构型模式:装饰模式

发表于 2019-04-29   |     |   阅读次数

文章首发:
结构型模式:装饰模式

花

七大结构型模式之四:装饰模式。

简介

姓名 :装饰模式

英文名 :Decorator Pattern

价值观 :人靠衣装,类靠装饰

个人介绍 :
Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
(来自《设计模式之禅》)

你要的故事

夏天到了,吃货们期待的各种各样冷冻零食就要大面积面向市场,什么冰淇淋、雪糕、冰棍等等。今天的装饰模式不讲这些都受欢迎的零食,讲讲那乌黑滴龟苓膏。不知道大伙们喜不喜欢吃龟苓膏,我是挺喜欢的,不喜欢的人很多都闲它苦,应该没有人愿意在没加任何糖类的情况下吃龟苓膏。很多糖水店会提供几种龟苓膏,比如蜂蜜龟苓膏、牛奶龟苓膏。下面我们空想出一个场景来。

天气到了 30℃,小明和小红加班到了 10 点,一起下班,路过一家糖水店,小红萌生了吃糖水解解热的想法,小明最近涨薪,就提出要请小红吃糖水,他们进去糖水店,小红想着好久没吃龟苓膏了,就想吃吃,怀念一下童年那段在农村夜晚吃龟苓膏的时光。糖水店里面有 3 种龟苓膏,一种是普通龟苓膏(这老板居然提供不加任何糖分的,过分了),一种是蜂蜜龟苓膏,另外一种是牛奶龟苓膏,小明点了一份蜂蜜龟苓膏,小红想加蜂蜜和牛奶,就咨询了老板娘,能否同时加蜂蜜和牛奶,老板娘用那东北腔爽快地回复小红:行。小明和小红就等龟苓膏上桌。。。脑洞到这。

我们来把这个故事套入到装饰模式里去。上面故事里老板卖 3 种龟苓膏,而都不满足小红的需求,小红想要的是蜂蜜牛奶龟苓膏,如果用继承来实现龟苓膏,那就无法满足小红的要求了,因为继承直接固定了龟苓膏的做法,加什么就是什么,要蜂蜜牛奶龟苓膏,那就需要另外一个龟苓膏类代表蜂蜜牛奶龟苓膏;而用装饰模式则不同,下面看看装饰模式的实现代码。

龟苓膏抽象类,该类定义了制作龟苓膏的抽象方法。

1
2
3
4
5
6
7
8
9
10
11
/**
* 龟苓膏
*/
abstract class HerbalJelly {

/**
* 制作龟苓膏方法
*/
public abstract void process();

}

老板提供的最基本的龟苓膏,这种龟苓膏不加任何料,就是那苦苦的龟苓膏,我们称它为普通龟苓膏。

1
2
3
4
5
6
7
8
9
10
11
/**
* 普通龟苓膏
*/
class CommonHerbalJelly extends HerbalJelly {

@Override
public void process() {
System.out.println("盛一碗龟苓膏");
}

}

另外 2 种龟苓膏:蜂蜜龟苓膏和牛奶龟苓膏,不是用继承实现,而是用装饰器实现,我们可以发现这 2 种龟苓膏都是基于上面普通龟苓膏添加不同的糖类食品制作而成。下面实现一个抽象类充当装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 龟苓膏装饰器
*/
abstract class Decorator extends HerbalJelly {

private HerbalJelly herbalJelly;

public Decorator(HerbalJelly herbalJelly) {
this.herbalJelly = herbalJelly;
}

@Override
public void process() {
this.herbalJelly.process();
}
}

接下来就根据上面的龟苓膏装饰器来实现蜂蜜龟苓膏和牛奶龟苓膏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 蜂蜜龟苓膏
*/
class HoneyHerbalJelly extends Decorator{

public HoneyHerbalJelly(HerbalJelly herbalJelly) {
super(herbalJelly);
}

@Override
public void process() {
super.process();
System.out.println("加蜂蜜");
}
}

/**
* 牛奶龟苓膏
*/
class MilkHerbalJelly extends Decorator{

public MilkHerbalJelly(HerbalJelly herbalJelly) {
super(herbalJelly);
}

@Override
public void process() {
super.process();
System.out.println("加牛奶");
}
}

下面提供我们的测试代码,还记得上面说的,小明要了一碗蜂蜜龟苓膏,小红则要了一碗蜂蜜牛奶龟苓膏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DecoratorTest {

public static void main(String[] args) {
CommonHerbalJelly commonHerbalJelly = new CommonHerbalJelly();
HoneyHerbalJelly honeyHerbalJelly = new HoneyHerbalJelly(commonHerbalJelly);
// 小明的蜂蜜龟苓膏
honeyHerbalJelly.process();

MilkHerbalJelly milkHerbalJelly = new MilkHerbalJelly(honeyHerbalJelly);
// 小红的蜂蜜牛奶龟苓膏
milkHerbalJelly.process();
}

}

打印结果:
盛一碗龟苓膏
加蜂蜜
盛一碗龟苓膏
加蜂蜜
加牛奶

我们看到,小明的龟苓膏只加蜂蜜,小红的龟苓膏加了蜂蜜和牛奶,这样就很简单的满足了小红的要求。

总结

装饰模式在一些类与类之间有叠加效应(也就是给一个类增加附加功能)的场景中非常好用,它可以说是继承的替代品,有更好的扩展性,也比较灵活。在 Java JDK 源码中也大面积用到了装饰模式,比如:java.io.BufferedInputStream(InputStream)。学完基础知识后,可以看看源码中是怎么实现的,巩固知识。

推荐阅读

结构型模式:组合模式

结构型模式:桥接模式

结构型模式:适配器模式

公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
加个人微信备注『教程』获取架构师、机器学习等教程

LieBrother

1…345…24
LieBrother

LieBrother

当才华撑不起野心时,应该静下心来学习;当能力驾驭不了目标时,应该沉下心来历练。

120 日志
38 分类
138 标签
© 2016 - 2019 LieBrother
由 Hexo 强力驱动
主题 - NexT.Mist
本站访客数人次  |  本站总访问量次