Ethan's Blog


  • Home

  • Archives

  • Tags

  • Search

Facade Design Pattern

Posted on 2020-12-07

门面模式的原理与实现

门面模式(Facade Design Pattern)是这样定义的:

Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.

翻译成中文就是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。除此之外,我还要强调一下,门面模式定义中的“子系统(subsystem)”也可以有多种理解方式。它既可以是一个完整的系统,也可以是更细粒度的类或者模块。

门面模式的应用场景举例

实际上,它除了解决易用性问题之外,还能解决其他很多方面的问题。

解决易用性问题

门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。比如,Linux 系统调用函数就可以看作一种“门面”。它是 Linux 操作系统暴露给开发者的一组“特殊”的编程接口,它封装了底层更基础的 Linux 内核调用。再比如,Linux 的 Shell 命令,实际上也可以看作一种门面模式的应用。它继续封装系统调用,提供更加友好、简单的命令,让我们可以直接通过执行命令来跟操作系统交互。

我们知道,类、模块、系统之间的“通信”,一般都是通过接口调用来完成的。接口设计的好坏,直接影响到类、模块、系统是否好用。所以,我们要多花点心思在接口设计上。我经常说,完成接口设计,就相当于完成了一半的开发任务。只要接口设计得好,那代码就差不到哪里去。

接口粒度设计得太大,太小都不好。太大会导致接口不可复用,太小会导致接口不易用。在实际的开发中,接口的可复用性和易用性需要微妙的权衡。针对这个问题,我的一个基本的处理原则是,尽量保持接口的可复用性,但针对特殊情况,允许提供冗余的门面接口,来提供更易用的接口。

Read more »

Adapter Design Pattern

Posted on 2020-12-05

适配器模式的原理与实现

适配器模式(Adapter Design Pattern)是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。

适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。具体的代码实现如下所示。其中,ITarget 表示要转化成的接口定义。Adaptee 是一组不兼容 ITarget 接口定义的接口,Adaptor 将 Adaptee 转化成一组符合 ITarget 接口定义的接口:

Read more »

Decorator Design Pattern

Posted on 2020-12-05

Java IO 类的“奇怪”用法

Java IO 类库非常庞大和复杂,有几十个类,负责 IO 数据的读取和写入。如果对 Java IO 类做一下分类,我们可以从下面两个维度将它划分为四类:

针对不同的读取和写入场景,Java IO 又在这四个父类基础之上,扩展出了很多子类。具体如下所示:

Read more »

Bridge Design Pattern

Posted on 2020-12-05

桥接模式的原理解析

桥接模式(Bridge Design Pattern)的定义:

Decouple an abstraction from its implementation so that the two can vary independently. – GoF

翻译成中文就是:将抽象和实现解耦,让它们可以独立变化。GoF 给出的定义非常的简短,单凭这一句话,估计没几个人能看懂是什么意思。所以,我们通过 JDBC 驱动的例子来解释一下。JDBC 驱动是桥接模式的经典应用。我们先来看一下,如何利用 JDBC 驱动来查询数据库。具体的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
Class.forName("com.mysql.jdbc.Driver"); // 加载及注册 JDBC 驱动程序
String url = "jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password";
Connection con = DriverManager.getConnection(url);
Statement stmt = con.createStatement();
String query = "select * from test";
ResultSet rs = stmt.executeQuery(query);
while(rs.next())
{
rs.getString(1);
rs.getInt(2);
}

如果我们想要把 MySQL 数据库换成 Oracle 数据库,只需要把第一行代码中的 com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver 就可以了。当然,也有更灵活的实现方式,我们可以把需要加载的 Driver 类写到配置文件中,当程序启动的时候,自动从配置文件中加载,这样在切换数据库的时候,我们都不需要修改代码,只需要修改配置文件就可以了。

如此优雅的数据库切换是如何实现的呢?源码之下无秘密,我们先从 com.mysql.jdbc.Driver 这个类的代码看起:

Read more »

Proxy Design Pattern

Posted on 2020-12-02

代理模式的原理解析

代理模式(Proxy Design Pattern)的原理和代码实现都不难掌握。它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。

我们开发了一个性能计数器 – MetricsCollector 类,在业务系统中,我们采用如下方式来使用这个 MetricsCollector 类:

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
public class UserController
{
//...省略其他属性和方法...
private MetricsCollector metricsCollector; // 依赖注入

public UserVo login(String telephone, String password)
{
long startTimestamp = System.currentTimeMillis();

//...省略 login 逻辑...

long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("login", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);

//...返回 UserVo 数据...
}

public UserVo register(String telephone, String password)
{
long startTimestamp = System.currentTimeMillis();

//...省略 register 逻辑...

long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("register", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);

//...返回 UserVo 数据...
}
}
Read more »
1…343536…55
necusjz

necusjz

271 posts
16 tags
© 2016 - 2026 necusjz
Powered by Hexo
Theme - NexT.Mist