嗨哈布罗夫斯克 联系弗拉迪斯拉夫·罗丹(Vladislav Rodin)。我目前正在OTUS门户上教授有关软件体系结构和高负载软件体系结构的课程。这次,我决定为即将开始的新课程“建筑与设计模式”写一些版权材料。享受阅读。
介绍
在克雷格·拉曼(Craig Larman)的《应用UML和模式》第三版中描述了GRASP模式是GoF模式的概括,也是OOP原理的直接结果。它们补充了逻辑阶梯中缺少的步骤,使您可以从OOP原理中获取GoF模式。GRASP模板很可能不是设计模式(如GoF的),而是类之间责任分配的基本原则。实践表明,它们并不是很流行,但是,使用完整的GRASP模式集对设计的类进行分析是编写良好代码的前提。GRASP模板的完整列表包含9个元素:- 信息专家
- 创作者
- 控制者
- 低耦合
- 高凝聚力
- 多态性
- 纯加工
- 间接的
- 受保护的版本
我建议考虑清单中最明显,最重要的模式:信息专家。信息专家
措辞
避免科学的表述,这种模式的实质可以表示如下:信息应在包含信息的地方进行处理。违例
尽管表面上看起来很简单明了,但我可以肯定,在任何项目的代码中,您都会发现许多违反该原理的行为。考虑最简单的类系统:Order(订单),其中包含OrderItem'ov(订单行)的列表,其元素依次包含Good(产品)及其数量,产品可能包含例如价格,名称等:@Getter
@AllArgsConstructor
public class Order {
private List<OrderItem> orderItems;
private String destinationAddress;
}
@Getter
@AllArgsConstructor
public class OrderItem {
private Good good;
private int amount;
}
@Getter
@AllArgsConstructor
public class Good {
private String name;
private int price;
}
我们有一个简单的任务:计算订单金额。如果您对解决此问题的想法不是很周到,则可以立即在与Order类的对象一起使用的客户端代码中编写类似以下内容:public class Client {
public void doSmth() {
}
private int getOrderPrice(Order order) {
List<OrderItem> orderItems = order.getOrderItems();
int result = 0;
for (OrderItem orderItem : orderItems) {
int amount = orderItem.getAmount();
Good good = orderItem.getGood();
int price = good.getPrice();
result += price * amount;
}
return result;
}
}
让我们分析这个解决方案。首先,如果我们开始添加与定价相关的业务逻辑,则Client :: getOrderPrice方法代码不仅将不可避免地增长,而且还将被各种if-s包围(养老金领取者折扣,假期折扣,批发采购),最终将导致无法读取此代码,更不用说更改。其次,如果构建UML图,则可以发现Client类最多依赖于3个类:Order,OrderItem和Good。它绘制了使用这些类的所有业务逻辑。这意味着如果我们要与Order分开重用OrderItem或Good(例如,计算仓库中剩余的货物价格),我们根本无法做到这一点,因为业务逻辑位于客户代码中,这将不可避免地导致代码重复。在此示例中,就像几乎所有存在get'ov链的地方一样,违反了Information Expert原则,因为客户端代码处理信息并包含其Order。应用实例
让我们尝试根据以下原则重新分配责任:@Getter
@AllArgsConstructor
public class Order {
private List<OrderItem> orderItems;
private String destinationAddress;
public int getPrice() {
int result = 0;
for(OrderItem orderItem : orderItems) {
result += orderItem.getPrice();
}
return result;
}
}
@Getter
@AllArgsConstructor
public class OrderItem {
private Good good;
private int amount;
public int getPrice() {
return amount * good.getPrice();
}
}
@Getter
@AllArgsConstructor
public class Good {
private String name;
private int price;
}
public class Client {
public void doSmth() {
Order order = new Order(new ArrayList<>(), "");
order.getPrice();
}
}
现在信息在包含它的类中进行处理,客户端代码仅取决于Order,而不怀疑其内部结构,并且Order,OrderItem和Good或OrderItem和Good类可以组装到一个单独的库中,该库可用于项目的各个部分。结论
封装带来的信息专家是GRASP责任分担的最基本原则之一。通过提高对代码的感知的简易性(最少惊奇的原理),增加重用的可能性并减少类之间的连接数,可以轻松地确定并消除它的违反。我们邀请您参加一个免费的网络研讨会,在该框架内可以研究整体应用程序,多层和无服务器架构的功能。仔细研究事件驱动系统,面向服务的系统和微服务体系结构。