解耦

解耦总的一句话来说,减少依赖,抽象业务和逻辑,让各个功能实现独立。

 

一.程序的耦合关系以及解耦的方式

1.耦合与解耦的概念

耦合: 在软件工程中,对象之间的耦合度就是对象之间的依赖性。对象之间的耦合越高,维护成本越高,因此对象的设计应使类和构件之间的耦合最小

解耦:在软件工程中,降低耦合度即可以理解为解耦,模块间有依赖关系必然存在耦合,理论上的绝对零耦合是做不到的,但可以通过一些现有的方法将耦合度降至最低

2.程序中存在的耦合关系与解耦的方式

2.1 耦合简单的例子:

1
2
3
4
5
6
7
8
9
public class A{
public int i;
}

public class B{
public void put(A a){
System.out.println(a.i);
}
}

以上代码就属于强耦合,B类中方法put要执行必须需要A类中的int属性i,缺了A,B中方法就不能执行

2.2 使用面向接口的编程方式实现上面例子的解耦:

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
 public interface IBase{
void say();
}

public class A implements IBase{

@Override
public void say() {
System.out.println("I am A");
}
}

public class B implements IBase{

@Override
public void say() {
System.out.println("I am B");
}
}

public class C{
public void put(IBase base){
base.say();
}
}

这只是其中的一种情况

2.3 根据耦合程度分类


总结:
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。

2.4 解耦

解耦的本质就是将类之间的直接关系转换成间接关系,不管是类向上转型还是接口回调都是在类之间加了一层,将原来的直接关系变成间接关系,使得两类对中间层是强耦合,两类之间变成弱耦合关系。

(a)采用现有设计模式实现解耦,如事件驱动模式、观察者模式、责任链模式等都可以达到解耦的目的;
(b)采用面向接口的方式编程,而不是用直接的类型引用,除非在最小内聚单元内部。但使用该方法解耦需要注意不要滥用接口。
(c)高内聚,往往会带来一定程度的低耦合度。高内聚决定了内部自行依赖,对外只提供必须的接口或消息对象,那么由此即可达成较低的耦合度。
( d )注解,以注解的方式,将方法,属性注入依赖,实现高扩展性。

解耦总的一句话来说,减少依赖,抽象业务和逻辑,让各个功能实现独立。

2.5 内聚与耦合

内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。
耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。
程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
 
 
解耦的原则:

做业务不要先考虑“解耦“,而是要先满足业务流程。即你的程序的结构应该是一个个纵向的业务流,从controller到最后的数据存储。不同的业务流不会相互干扰。

等到你做了很多个业务流后,再去尝试辨识哪些地方有可能是能公用的,再去尝试去复用。公用的前提是

  • 这块代码几乎很少改
  • 这块代码有比较合理的业务抽象 —— 即从人类直觉上这给地方抽出来也是说得通的
  • 就算这块代码要改。他的改动对其他依赖造成的影响总是符合常识的,而不是会引发一大堆问题

如果得不到这样的特性,即使代码看起来有相似之处,也不要去抽。错误的抽象才是代码维护的大敌。一旦做了,你根本控制不了你的修改的影响范围和影响程度。

题主对解耦的理解也有偏颇。从题目上看,似乎“逻辑不写一起“就解耦了,而写在一起就耦合。实际上并不是这样的。不要认为任何业务逻辑可以做任何细粒度的拆解。从业务角度,一个业务是一个“步骤的集合”。总会有第一步干什么,第二步干什么,等等。很多时候,这些步骤写一起才更容易看懂,更容易修改和维护。

更精细的区分,一个业务的逻辑大概可以分为两类:

  • 业务直接相关的主逻辑。比如你要实现下单买东西,那么创建订单、扣款是主逻辑。这些逻辑必须要写到一起,而且往往用同一个事务包起来保证一致性。如果主逻辑非常复杂,就尝试用多个层级来拆解这些流程,但他们还是在一起。
  • 业务辅助相关的逻辑。比如更新计数、更新ES的搜索数据、发一个业务统计log等。这些内容可以不要掺合到主逻辑中。可以用AOP,事件队列(单机的/分布式的)的形式来解耦。

但解耦是有前提的。事实上解耦会让系统结构更复杂了。比如一个业务接口调用完了,计数却没有增加,或者晚了很久才增加。要调查问题,就需要系统监控等做的相当到位。团队的相关模块负责人可以有办法来精确的管理跨系统的数据流,能快速定位错误原因。

同时,你的产品设计也可能需要跟着更改。比如计数可能因为最终一致性而暂时不准,会引起用户的困惑。这时候产品设计上可能需要一个临时的“假的,但是符合用户直觉“的计数,或者以各种方式隐藏计数等措施来对产品做调整。

解耦不是写业务代码的最终目标,用可以接受的性价比进行业务开发和代码维护才是。如果你的team里没有那么多人来各自负责独立的模块,也没有很好的INFRA支持,而是很少数几个人处理所有逻辑,那整体看下来还不如把代码都写一起。

猜你喜欢

转载自www.cnblogs.com/jacksplwxy/p/9589280.html