文档章节

阿里P7大牛细说架构——设计模式专栏

别打我会飞
 别打我会飞
发布于 2018/11/25 14:23
字数 3170
阅读 107
收藏 3

设计模式介绍

对于有经验的开发人员,学习设计模式有助于我们找到在软件开发过程中所面临的问题的最佳解决方案。一直以来软件都是为了用来解决现实生活中遇到的复杂问题而存在,设计模式(Design pattern)就像一套基础武功心法,每一式都代表了一类问题的最佳实践,且可根据实际情况组合使用。本系列文章笔者将带大家一起从零开始学习设计模式,后面会逐个剖析23种设计模式在Java中的具体实现,读者需具备基本的Java编程概念。

文末有福利放送,感谢读者的阅读。

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的

设计模式可以通过提供经过测试和验证的开发范例来加快开发过程

重用设计模式有助于防止可能导致重大问题的微妙问题,同时也提高了熟悉模式的程序员和架构师的代码可读性

什么是GOF(四人帮,全拼Gang of Four)

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。

  • 对接口编程而不是对实现编程。
  • 优先使用对象组合而不是继承。

用途

设计模式的主要用途有两个,一是提供了一个标准的术语系统,且具体到特定的场景。如单例设计模式意味着使用单个对象,这样所有熟悉单例设计模式的开发人员都能使用单个对象,并且可以通过这种方式告诉对方,程序使用的是单例模式。二是提供了最佳的实践,设计模式已经经历了很长一段时间的发展,它们提供了软件开发过程中面临的一般问题的最佳解决方案。学习这些模式有助于经验不足的开发人员通过一种简单快捷的方式来学习软件设计

设计模式的类型

根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。还有另一类设计模式:

J2EE设计模式

。这些设计模式从易到难可以分为三个等级:Difficulty-Beginner(难度-初学者), Difficulty-Intermediate(难度-中级) & Difficulty-Expert(难度-专家),后续文章我将从易到难的为大家介绍不同类型的设计模式。

阿里P7大牛细说架构——设计模式专栏

 

阿里P7大牛细说架构——设计模式专栏

 

阿里P7大牛细说架构——设计模式专栏

 

下面一张图片整体描述了一下设计模式之间的关系:

阿里P7大牛细说架构——设计模式专栏

 

设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

设计模式的思考

在学习和理解设计模式之前,你应该熟悉一些编程/软件设计原则。 所有的设计都应该尽可能简单,从最简单的事情开始,慢慢延伸,这可能是工作学习的原理。

只有在实际要求可扩展性,需要复杂性和套路模式时,才应该引入它们(设计模式)。 一旦你熟悉了这些设计模式的概念,你就可以根据实际工程情况选择最适合的模式来优雅的实现工程目标。

工厂模式

工厂模式也被称之为虚拟构造函数(Virtual Constructor),是Java中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

意图

定义用于创建对象的接口,但是让子类决定实例化哪个类。factory方法允许类将实例化推迟到子类

主要解决:接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

解释

现实世界的例子

铁匠制造武器。精灵需要精灵武器,兽人需要兽人武器。根据手头的顾客,召集合适类型的铁匠

简而言之

它提供了一种将实例化逻辑委托给子类的方法

维基百科说

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.(在基于类的编程中,factory方法模式是一种创建模式,它使用factory方法来处理创建对象的问题,而不必指定将要创建的对象的确切类。这是通过调用factory方法(在接口中指定并由子类实现,或者在基类中实现并可选地由派生类重写)来实现的,而不是通过调用构造函数来实现的。)

程序代码示例

以现实世界的例子铁匠制造武器为例子,需要什么样的武器类型我们就召唤对应类型的铁匠。程序类图如下:

阿里P7大牛细说架构——设计模式专栏

 

铁匠接口实现类图.png

首先我们有一个铁匠接口(定义了一个制造武器的方法)和一些精灵铁匠、兽人铁匠实现类:

public interface Blacksmith {
 Weapon manufactureWeapon(WeaponType weaponType);
}
public class ElfBlacksmith implements Blacksmith {
 public Weapon manufactureWeapon(WeaponType weaponType) {
 return new ElfWeapon(weaponType);
 }
}
public class OrcBlacksmith implements Blacksmith {
 public Weapon manufactureWeapon(WeaponType weaponType) {
 return new OrcWeapon(weaponType);
 }
}
复制代码

其次我们有一个武器接口(定义了一个获取武器类型的方法)和一些精灵武器、兽人武器实现类:

/**
* Weapon interface.
*/
public interface Weapon {
 WeaponType getWeaponType();
}
/**
* ElfWeapon.
*/
public class ElfWeapon implements Weapon {
 private WeaponType weaponType;
 public ElfWeapon(WeaponType weaponType) {
 this.weaponType = weaponType;
 }
 @Override
 public String toString() {
 return "Elven " + weaponType;
 }
 @Override
 public WeaponType getWeaponType() {
 return weaponType;
 }
}
/**
* OrcWeapon.
*/
public class OrcWeapon implements Weapon {
 private WeaponType weaponType;
 public OrcWeapon(WeaponType weaponType) {
 this.weaponType = weaponType;
 }
 @Override
 public String toString() {
 return "Orcish " + weaponType;
 }
 @Override
 public WeaponType getWeaponType() {
 return weaponType;
 }
}
复制代码

最后,随着顾客的到来,正确类型的铁匠被召唤出来,要求制造武器

public class App {
 private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
 private final Blacksmith blacksmith;
 
 /**
 * Creates an instance of <code>App</code> which will use <code>blacksmith</code> to manufacture 
 * the weapons for war.
 * <code>App</code> is unaware which concrete implementation of {@link Blacksmith} it is using.
 * The decision of which blacksmith implementation to use may depend on configuration, or
 * the type of rival in war.
 * @param blacksmith a non-null implementation of blacksmith
 */
 public App(Blacksmith blacksmith) {
 this.blacksmith = blacksmith;
 }
 
 /**
 * Program entry point
 * 
 * @param args command line args
 */
 public static void main(String[] args) {
 // Lets go to war with Orc weapons
 App app = new App(new OrcBlacksmith());
 app.manufactureWeapons();
 
 // Lets go to war with Elf weapons
 app = new App(new ElfBlacksmith());
 app.manufactureWeapons();
 }
 
 private void manufactureWeapons() {
 Weapon weapon;
 weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
 LOGGER.info(weapon.toString());
 weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
 LOGGER.info(weapon.toString());
 }
}
复制代码

运行App程序结果:

阿里P7大牛细说架构——设计模式专栏

 

app类运行结果输出.png

适用场景

当遇到如下三种情况时,应使用工厂模式:

  1. 一个类不能预测它必须创建的对象的类
  2. 一个类希望它的子类指定它创建的对象
  3. 类将责任委托给几个助手子类中的一个,并且你希望本地化哪个助手子类是委托的责任

Java中的现实例子

  • java.util.Calendar
  • java.util.ResourceBundle
  • java.text.NumberFormat
  • java.nio.charset.Charset
  • java.net.URLStreamHandlerFactory
  • java.util.EnumSet
  • javax.xml.bind.JAXBContext

优缺点

优点:

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  3. 屏蔽产品的具体实现,调用者只关心产品的接口

缺点:

每次增加一个产品时,都需要增加一个具体实现类和修改对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事

最后

工厂模式作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂模式,比如设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个通讯接口。

对于简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式,因为使用工厂模式必然要引入一个工厂类,这会增加系统的复杂度,切不可为了设计模式而模式。

之后我们将在工厂模式的基础上继续延伸介绍抽象工厂模式,难度系统为中级

推荐一个交流学习圈子群:697-57-9751 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多:

 

© 著作权归作者所有

别打我会飞
粉丝 99
博文 184
码字总数 438122
作品 0
朝阳
架构师
私信 提问
迈向大牛的重要一步——掌握设计模式

IT职场的小菜经常有这样的疑问: 为什么一个相似的功能,大牛一会儿就搞定,然后悠闲地品着下午茶逛淘宝;而自己加班加点搞到天亮还做不完。 为什么用户提出需求变更后,大牛只需潇洒地敲敲键...

一枚Sir
2015/04/10
0
0
现代Java进阶之路必备技能——2019 版

Java技术的学习阶段有三 第1个是java基础,比如对集合类,并发,IO,JVM,内存模型,泛型,异常,反射,等有深入了解。 第2个是全面的互联网技术相关知识,比如redis,mogodb,nginx,代码自...

Java小仙女
03/26
0
0
编程中的那些经典套路——设计模式汇总

在正式阅读前,我先谈谈我们该用什么姿势和心态学习设计模式: 如果你还没有过多的编程经验(泛指半年以下),我建议你把它当做小说来看,能看懂多少是多少,因为半年以下经验的程序员用到设...

gzchen
2018/08/27
0
0
Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei
2018/05/26
0
0
《JavaScript设计模式与开发实践》最全知识点汇总大全

系列文章: 《JavaScript设计模式与开发实践》基础篇(1)—— this、call 和 apply 《JavaScript设计模式与开发实践》基础篇(2)—— 闭包和高阶函数 《JavaScript设计模式与开发实践》模式...

嗨呀豆豆呢
01/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

solidity智能合约中tx.origin的正确使用场景

简介 tx.origin是Solidity的一个全局变量,它遍历整个调用栈并返回最初发送调用(或事务)的帐户的地址。在智能合约中使用此变量进行身份验证会使合约容易受到类似网络钓鱼的攻击。 但针对t...

程序新视界
19分钟前
0
0
代码详解:基于Python建立任意层数的深度神经网络

全文共6359字,预计学习时长20分钟或更长 图片来源:pexels.com/@divinetechygir 在这篇指南中,我们将建立起一个任意层数的深度神经网络。这个神经网络可以应用于二元分类的监督学习问题。 ...

读芯术
21分钟前
0
0
使用mybatis-plus-gennretor代码生成器生成代码

1导入需要的jar包 <dependencies> <!-- mp依赖 mybaits-plus 会自动维护mybaits jar包 所以不用加入了 防止版本冲突 --> <dependency> <groupId>com.ba......

小小小施爷
40分钟前
0
0
巨杉Tech | 微服务趋势下的数据库设计与应用简析

上周五(7月12日)巨杉数据库参与了由得到App主办八里庄技术沙龙活动,分享主题是关于分布式数据库架构与实战。 以下就是根据巨杉数据库现场分享的内容进行的分享实录整理。 巨杉数据库简介 ...

巨杉数据库
54分钟前
68
0
借助URLOS快速安装AliSQL

环境需求 最低硬件配置:1核CPU,1G内存(1+1)提示:如果你的应用较多,而主机节点的硬件配置较低,建议在部署节点时开通虚拟虚拟内存; 生产环境建议使用2G或以上内存; 推荐安装系统:Ubu...

躲猫猫_007
56分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部