什么是设计模式?
设计模式是软件设计中前人对相同表征的问题,抽象出的可重复利用的解决方案。也是编码中针对特定场景问题的最佳实践。理解和掌握设计模式,不但可以提高我们编码的效率和质量,同时可以节省开发人员之间沟通的时间成本。
面试官:谈谈你知道的设计模式?
经典回答
设计模式大致可分为以下三类:
-
1.创建型模式,是对对象创建过程的各种问题和解决方案的总结,这其中包括 工厂模式,单例模式,构建器模式,原型模式。
-
2.结构型模式,是针对软件设计结构的总结,它关注于类,对象继承,组合方式的实践经验。常见的结构型模式有 桥接模式,适配器模式,装饰器模式,代理模式,组合模式,外观模式,享元模式等。
-
3.行为型模式,是从类或者对象之间的交互,职责划分等角度总结的模式。比较常见的行为型模式有 策略模式,解释器模式,命令模式,观察者模式,迭代器模式,模板方法模式,访问者模式。
知识拓展
上面是比较典型的回答,但是我们在回答的时候最好附上一些实例,比如说,装饰器模式,我们可以举例 Java I/O
框架,InputStream
是一个抽象类,标准库还提供了 FileInputStream
, BufferedInputStream
, ByteArrayInputStream
等各种不同的拓展类,这些子类从不同的角度对 InputSteam
进行了功能拓展,也是经典的装饰器模式应用案例。
如何识别装饰者模式?
识别代码中是否使用装饰者模式,可以通过识别类设计特征来进行判断,也就是其类的构造函数以相同的抽象类或者接口为输入函数。因为装饰器模式本质上是包装同类型实例,来达到 “装饰” 的作用。
例如,BufferedInputStream
经过包装,为输入流增加缓存的功能:
public BufferedInputStream(InputStream in)
下图简单总结了 InputStream
的装饰器模式实践类图:
接下来再来说说创建型模式。其中工厂模式更是在代码中随处可见,这里举个相对不同的 API 设计实践。如 JDK 最新版本的 HTTP/2 Client API, 下面这个 HttpRequest
创建过程就是典型的构造器模式,通常还会被设计成 fluent 风格 的 API, 你也可以叫做方法链。
HttpRequest request = HttpRequest.newBuilder(new URI(uri))
.header(headerAlice, valueAlice)
.headers(headerBob, value1Bob,
headerCarl, valueCarl,
headerBob, value2Bob).GET()
.build();
使用构造器模式有什么好处?
通过使用构造器模式,我们可以比较优雅的解决构建比较复杂对象的麻烦。试想一下,如果我们不使用构造器,则需要通过构造函数来实现对象的构建,这样我们需要为每一种可能的输入参数的组合编写对应的构造函数,这样会使代码的可阅读性和可维护性变得很差。
设计模式中的单例模式,也是经常被考官问到的一个知识点,具体可参考我的另一篇博文 《Java 面试之单例模式》
上面说了不少代码实践,下面一起来看看主流开源框架, 如 Spring 等是如何在 API 设计中使用设计模式的:
-
BeanFactory
和ApplicationContext
应用了工厂模式; -
在
Bean
的创建中,Spring 为不同的scope
定义的对象,提供了单例和原型等模式的实现; -
AOP 模块则是使用了 代理模式, 装饰器模式,适配器模式等;
-
各种事件监听器,则是使用了观察者模式;
-
Spring JdbcTemplte
等则是应用了模板模式。
总结
今天我们主要谈及什么是设计模式,以及设计模式大致分为三种类型,并从装饰器模式,构造器模式,单例模式入手举例说明。又说了 Spring 框架中,常见模块中用到的设计模式。最后,需要注意的是,设计模式是个好东西,但也不能滥用和过度设计,需要从实际业务为出发点。