跨境支付(五):可应用的领域有哪些?

王争《设计模式之美》笔记

如何进行面向对象设计?

面向对象分析的产出是详细的需求描述,那面向对象设计的产出就是类。在面向对象设计环节,我们将需求描述转化为具体的类的设计。我们把这一设计环节拆解细化一下,主要包含以下几个部分:

  • 划分职责进而识别出有哪些类;
  • 定义类及其属性和方法;
  • 定义类与类之间的交互关系;
  • 将类组装起来并提供执行入口。

1. 划分职责进而识别出有哪些类

(1)通过映射现实世界中的事物的方式来定义类的

(2)把需求描述中的名词罗列出来,作为可能的候选类,然后再进行筛选

(3)根据需求描述,把其中涉及的功能点,一个一个罗列出来,然后再去看哪些功能点职责相近,操作同样的属性,可否应该归为同一个类。

逐句拆解上篇中需求描述之后,得到的功能点列表:

1. 把URL、AppID、密码、时间戳拼接为一个字符串;

2. 对字符串通过加密算法加密生成token;

3. 将token、AppID、时间戳拼接到URL中,形成新的URL;

4. 解析URL,得到token、AppID、时间戳等信息;

5. 从存储中取出AppID和对应的密码;

6. 根据时间戳判断token是否过期失效;

7. 验证两个token是否匹配;

我们可以粗略地得到三个核心的类:AuthToken、UrlCredentialStorage。AuthToken 负责实现1、2、6、7这四个操作;Url负责3、4两个操作;CredentialStorage 负责5这个操作。

2. 定义类及其属性和方法

AuthToken类相关的功能点有四个:

把URL、AppID、密码、时间戳拼接为一个字符串;

对字符串通过加密算法加密生成 token;

根据时间戳判断 token 是否过期失效;

验证两个 token 是否匹配。

Url 类相关的功能点有两个:

将 token、AppID、时间戳拼接到 URL 中,形成新的 URL;

解析 URL,得到 token、AppID、时间戳等信息。

CredentialStorage 类相关的功能点有一个:

从存储中取出 AppID 和对应的密码。

3. 定义类与类之间的交互关系

UML统一建模语言中定义了六种类之间的关系。它们分别是:泛化、实现、关联、聚合、组合、依赖。

泛化(Generalization)可以简单理解为继承关系。

实现(Realization)一般是指接口和实现类之间的关系。

聚合(Aggregation)是一种包含关系,A类对象包含B类对象,B类对象的生命周期可以不依赖A类对象的生命周期,也就是说可以单独销毁A类对象而不影响B对象。

组合(Composition)也是一种包含关系。A类对象包含B类对象,B类对象的生命周期依赖A类对象的生命周期,B类对象不可单独存在。

关联(Association)是一种非常弱的关系,包含聚合、组合两种关系。具体到代码层面,如果B类对象是A类的成员变量,那B类和A类就是关联关系。

依赖(Dependency)是一种比关联关系更加弱的关系,包含关联关系。不管是B类对象是A类对象的成员变量,还是A类的方法使用B类对象作为参数或者返回值、局部变量,只要B类对象和A类对象有任何使用关系,我们都称它们有依赖关系

本文中:泛化、实现、依赖的定义不变,组合关系替代 UML 中组合、聚合、关联三个概念,也就相当于重新命名关联关系为组合关系,并且不再区分UML中的组合和聚合两个概念。

4. 将类组装起来并提供执行入口

类定义好了,类之间必要的交互关系也设计好了,接下来我们要将所有的类组装在一起,提供一个执行入口。这个入口可能是一个 main() 函数,也可能是一组给外部用的 API接口。 通过这个入口,我们能触发整个代码跑起来。

接口鉴权并不是一个独立运行的系统,而是一个集成在系统上运行的组件,所以,我们封装所有的实现细节,设计了一个最顶层的 ApiAuthencator接口类,暴露一组给外部调用者 使用的 API接口,作为触发执行鉴权逻辑的入口。具体的类的设计如下所示:

设计模式之美(十二)如何利用面向对象设计和编程开发鉴权功能?

如何进行面向对象编程?

面向对象设计完成之后,我们已经定义清晰了类、属性、方法、类之间的交互,并且将所有的类组装起来,提供了统一的执行入口。接下来,面向对象编程的工作,就是将这些设计思路翻译成代码实现。有了前面的类图,这部分工作相对来说就比较简单了。所以,这里我只给出比较复杂的ApiAuthencator 的实现。

public interface ApiAuthencator {
void auth(String url);
void auth(ApiRequest apiRequest);
}

public class DefaultApiAuthencatorImpl implements ApiAuthencator {

private CredentialStorage credentialStorage;
public ApiAuthencator() {
this.credentialStorage = new MysqlCredentialStorage();
}
public ApiAuthencator(CredentialStorage credentialStorage) {
this.credentialStorage = credentialStorage;
}

@Override
public void auth(String url) {
ApiRequest apiRequest = ApiRequest.buildFromUrl(url);
auth(apiRequest);
}

@Override
public void auth(ApiRequest apiRequest) {
String appId = apiRequest.getAppId();
String token = apiRequest.getToken();
long timestamp = apiRequest.getTimestamp();
String originalUrl = apiRequest.getOriginalUrl();
AuthToken clientAuthToken = new AuthToken(token, timestamp);
if (clientAuthToken.isExpired()) {
throw new RuntimeException(\"Token is expired.\");
}
String password = credentialStorage.getPasswordByAppId(appId);
AuthToken serverAuthToken = AuthToken.generate(originalUrl, appId, password);
if (!serverAuthToken.match(clientAuthToken)) {
throw new RuntimeException(\"Token verfication failed.\");

}
}
}

辩证思考与灵活应用

整个软件开发本来就是一个迭代、修修补补、遇到问题解决问题的过程,是一个不断重构的过程。我们没法严格地按照顺序执行各个步骤。

重点回顾

面向对象分析的产出是详细的需求描述。面向对象设计的产出是类。在面向对象设计这一环节中,我们将需求描述转化为具体的类的设计。这个环节的工作可以拆分为下面四个部分。

1.划分职责进而识别出有哪些类

根据需求描述,我们把其中涉及的功能点,一个一个罗列出来,然后再去看哪些功能点职责相近,操作同样的属性,可否归为同一个类。

2.定义类及其属性和方法

我们识别出需求描述中的动词,作为候选的方法,再进一步过滤筛选出真正的方法,把功能点中涉及的名词,作为候选属性,然后同样再进行过滤筛选。

3.定义类与类之间的交互关系

UML 统一建模语言中定义了六种类之间的关系。它们分别是:泛化、实现、关联、聚合、 组合、依赖。我们从更加贴近编程的角度,对类与类之间的关系做了调整,保留四个关系: 泛化、实现、组合、依赖。

4.将类组装起来并提供执行入口

我们要将所有的类组装在一起,提供一个执行入口。这个入口可能是一个main()函数,也可能是一组给外部用的API 接口。通过这个入口,我们能触发整个代码跑起来。

课堂讨论

软件设计的自由度很大,这也是软件的复杂之处。不同的人对类的划分、定义、类之间交互的设计,可能都不大一样。那除了我今天给出的设计思路,你还有没有其他设计思路呢?

参考:https://time.geekbang.org/column/intro/250?code=gLit0LpsKZQ6vOVqS1htGOSAKYLCYeMuklw2dwajH-4%3D

上一篇

郑爽:我们一家我最丑!看到她爸妈照片,我是信了

下一篇

诸葛亮唯一一次犯错:杀了一个不该杀的大将,饶了一个该杀的小人

你也可能喜欢

  • 暂无相关文章!

发表评论

您的电子邮件地址不会被公开。 必填项已用 * 标注

提示:点击验证后方可评论!

插入图片
返回顶部