转载

编码至高法则-高内聚低耦合

此法则适合所有语言,咱们以 JavaScript Java 两个角度分析一下这个东东。

一、 javascript

有这样的一个页面, js css 代码都写在 html 页面中。

例如: gnj.html

v1

版本

1 <! DOCTYPE html >

2 < html  lang ="en" >

3 < head >

4 < meta  charset ="UTF-8" >

5 < meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >

6 < meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >

7 < title > Document </ title >

8 </ head >

9 < body >

10 < script >
11         document.write( " 高内聚低耦合demo "

);

12      </ script >

13 < style >
14     h1  {
15         background-color :  blueviolet ;
16      }
17      </ style >

18 < h1 > 标题 </ h1 >

19 </ body >

20 </ html >

21

这个页面承载了多个功能:定义 html 需要的 javascript 脚本,定义 html 需要的 css 样式,还有定义页面需要显示的元素。

这样的代码编写方式就像下面两个拼拼凑凑的动物:

龙:

编码至高法则-高内聚低耦合

角似鹿、头似牛、眼似虾、嘴似驴、腹似蛇、鳞似鱼、足似凤、须似人、耳似象

麋鹿:

编码至高法则-高内聚低耦合

角似鹿非鹿、鼻子似牛非牛、身体似驴非驴、尾巴似马非马

问题:代码内部比较臃肿,复用度很低。 js 不能被多个 html 复用, css 也不能被多个 html 复用。耦合性较高。

优化后的代码,如下:

v2 版本

gnj.js

1 document.write("高内聚低耦合demo");

h1.css

1 h1 {

2 background-color: blueviolet;

3 }

4

gnj_v2.html

1 <! DOCTYPE html >

2 < html  lang ="en" >

3 < head >

4 < meta  charset ="UTF-8" >

5 < meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >

6 < meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >

7 < title > Document </ title >

8 < script  src ="./gnj.js" ></ script >

9 < link  rel ="stylesheet"  type ="text/css"  href ="h1.css" />

10 </ head >

11 < body >

12

13 < h1 > 标题 </ h1 >

14 </ body >

15 </ html >

16

高内聚:模块内的事。模块内,联系越紧密,内聚性越高。

低耦合 :

模块间的事,相关的操作,不再直接相互依赖调用

二、 java

再来看一个 java 的中午吃饭过程的例子:

v0

版本

1 package com.gavin.controller;

2

3 import org.springframework.web.bind.annotation.GetMapping;

4 import org.springframework.web.bind.annotation.RestController;

5

6 /**
 7

* Created by gavinmiao on 2019/8/30

 8   */

9 @RestController

10 public class DemoController {

11 @GetMapping("/lunch")

12 public String haveLunch(){

13 StringBuilder builder =  new StringBuilder();

14 builder.append("<html>");

15 // 排队
16 builder.append(String.format("%s <br/>","--------------------------------------------"));

17 builder.append(String.format("%s <br/>","(^o^)开始排队(^o^)"));

18 builder.append(String.format("%s <br/>","1只羊"));

19 builder.append(String.format("%s <br/>","2只羊"));

20 builder.append(String.format("%s <br/>","3只羊"));

21 builder.append(String.format("%s <br/>","4只羊"));

22 builder.append(String.format("%s <br/>","5只羊"));

23 builder.append(String.format("%s <br/>","6只羊"));

24 builder.append(String.format("%s <br/>","7只羊"));

25 builder.append(String.format("%s <br/>","8只羊"));

26 builder.append(String.format("%s <br/>","9只羊"));

27 builder.append(String.format("%s <br/>","(-o-)结束排队(-o-)"));

28 // 点菜
29 builder.append(String.format("%s <br/>","--------------------------------------------"));

30 builder.append(String.format("%s <br/>","(^o^)开始点菜(^o^)"));

31 builder.append(String.format("%s <br/>","蒸羊羔"));

32 builder.append(String.format("%s <br/>","蒸熊掌"));

33 builder.append(String.format("%s <br/>","蒸鹿尾儿"));

34 builder.append(String.format("%s <br/>","烧花鸭"));

35 builder.append(String.format("%s <br/>","烧雏鸡"));

36 builder.append(String.format("%s <br/>","烧子鹅"));

37 builder.append(String.format("%s <br/>","卤猪"));

38 builder.append(String.format("%s <br/>","卤鸭"));

39 builder.append(String.format("%s <br/>","酱鸡"));

40 builder.append(String.format("%s <br/>","腊肉"));

41 builder.append(String.format("%s <br/>","松花"));

42 builder.append(String.format("%s <br/>","小肚儿"));

43 builder.append(String.format("%s <br/>","(-o-)结束点菜(-o-)"));

44

45 // 取餐
46 builder.append(String.format("%s <br/>","--------------------------------------------"));

47 builder.append(String.format("%s <br/>","(^o^)开始取餐(^o^)"));

48 builder.append(String.format("%s <br/>","一盘蒸羊羔"));

49 builder.append(String.format("%s <br/>","一盘蒸熊掌"));

50 builder.append(String.format("%s <br/>","一盘蒸鹿尾儿"));

51 builder.append(String.format("%s <br/>","一盘烧花鸭"));

52 builder.append(String.format("%s <br/>","一盘烧雏鸡"));

53 builder.append(String.format("%s <br/>","一盘烧子鹅"));

54 builder.append(String.format("%s <br/>","一盘卤猪"));

55 builder.append(String.format("%s <br/>","一盘卤鸭"));

56 builder.append(String.format("%s <br/>","一盘酱鸡"));

57 builder.append(String.format("%s <br/>","一盘腊肉"));

58 builder.append(String.format("%s <br/>","一盘松花"));

59 builder.append(String.format("%s <br/>","一盘小肚儿"));

60 builder.append(String.format("%s <br/>","(-o-)结束取餐(-o-)"));

61

62 // 用餐
63 builder.append(String.format("%s <br/>","--------------------------------------------"));

64 builder.append(String.format("%s <br/>","(^o^)开始用餐(^o^)"));

65 builder.append(String.format("%s <br/>","蒸羊羔好吃"));

66 builder.append(String.format("%s <br/>","蒸熊掌好吃"));

67 builder.append(String.format("%s <br/>","蒸鹿尾儿好吃"));

68 builder.append(String.format("%s <br/>","烧花鸭好吃"));

69 builder.append(String.format("%s <br/>","烧雏鸡好吃"));

70 builder.append(String.format("%s <br/>","烧子鹅好吃"));

71 builder.append(String.format("%s <br/>","卤猪好吃"));

72 builder.append(String.format("%s <br/>","卤鸭好吃"));

73 builder.append(String.format("%s <br/>","酱鸡好吃"));

74 builder.append(String.format("%s <br/>","腊肉好吃"));

75 builder.append(String.format("%s <br/>","松花好吃"));

76 builder.append(String.format("%s <br/>","小肚儿好吃"));

77 builder.append(String.format("%s <br/>","(-o-)结束用餐(-o-)"));

78 builder.append(String.format("%s <br/>","--------------------------------------------"));

79 builder.append("</html>");

80 return builder.toString();

81 }

82

83 }

84

代码运行如下:

编码至高法则-高内聚低耦合

仔细阅读以上代码,发现有很多重复的地方,比如分割线和添加字符串操作。基于这两个重复的地方,咱们可以优化一下。单独提供两个方法,一个获取分割线,另外一个处理字符串拼接。

V1

版本

1 package com.gavin.controller;

2

3 import org.springframework.web.bind.annotation.GetMapping;

4 import org.springframework.web.bind.annotation.RestController;

5

6 /**
 7

* Created by gavinmiao on 2019/8/30

 8   */

9 @RestController

10 public class DemoV1Controller {

11 @GetMapping("/v1/lunch")

12 public String haveLunch(){

13 StringBuilder builder =  new StringBuilder();

14 builder.append("<html>");

15 // 排队
16 appendStr(builder,getSeparator());

17 appendStr(builder,"(^o^)开始排队(^o^)");

18 appendStr(builder,"1只羊");

19 appendStr(builder,"2只羊");

20 appendStr(builder,"3只羊");

21 appendStr(builder,"4只羊");

22 appendStr(builder,"5只羊");

23 appendStr(builder,"6只羊");

24 appendStr(builder,"7只羊");

25 appendStr(builder,"8只羊");

26 appendStr(builder,"9只羊");

27 appendStr(builder,"(-o-)结束排队(-o-)");

28 // 点菜
29 appendStr(builder,getSeparator());

30 appendStr(builder,"(^o^)开始点菜(^o^)");

31 appendStr(builder,"蒸羊羔");

32 appendStr(builder,"蒸熊掌");

33 appendStr(builder,"蒸鹿尾儿");

34 appendStr(builder,"烧花鸭");

35 appendStr(builder,"烧雏鸡");

36 appendStr(builder,"烧子鹅");

37 appendStr(builder,"卤猪");

38 appendStr(builder,"卤鸭");

39 appendStr(builder,"酱鸡");

40 appendStr(builder,"腊肉");

41 appendStr(builder,"松花");

42 appendStr(builder,"小肚儿");

43 appendStr(builder,"(-o-)结束点菜(-o-)");

44

45 // 取餐
46 appendStr(builder,getSeparator());

47 appendStr(builder,"(^o^)开始取餐(^o^)");

48 appendStr(builder,"一盘蒸羊羔");

49 appendStr(builder,"一盘蒸熊掌");

50 appendStr(builder,"一盘蒸鹿尾儿");

51 appendStr(builder,"一盘烧花鸭");

52 appendStr(builder,"一盘烧雏鸡");

53 appendStr(builder,"一盘烧子鹅");

54 appendStr(builder,"一盘卤猪");

55 appendStr(builder,"一盘卤鸭");

56 appendStr(builder,"一盘酱鸡");

57 appendStr(builder,"一盘腊肉");

58 appendStr(builder,"一盘松花");

59 appendStr(builder,"一盘小肚儿");

60 appendStr(builder,"(-o-)结束取餐(-o-)");

61

62 // 用餐
63 appendStr(builder,getSeparator());

64 appendStr(builder,"(^o^)开始用餐(^o^)");

65 appendStr(builder,"蒸羊羔好吃");

66 appendStr(builder,"蒸熊掌好吃");

67 appendStr(builder,"蒸鹿尾儿好吃");

68 appendStr(builder,"烧花鸭好吃");

69 appendStr(builder,"烧雏鸡好吃");

70 appendStr(builder,"烧子鹅好吃");

71 appendStr(builder,"卤猪好吃");

72 appendStr(builder,"卤鸭好吃");

73 appendStr(builder,"酱鸡好吃");

74 appendStr(builder,"腊肉好吃");

75 appendStr(builder,"松花好吃");

76 appendStr(builder,"小肚儿好吃");

77 appendStr(builder,"(-o-)结束用餐(-o-)");

78 appendStr(builder,getSeparator());

79 builder.append("</html>");

80 return builder.toString();

81 }

82

83 private String getSeparator(){

84 return "--------------------------------------------";

85 }

86

87 private void appendStr(StringBuilder builder,String 啊我额){

88 builder.append(String.format("%s <br/>",啊我额));

89 }

90 }

91


代码运行如下:
编码至高法则-高内聚低耦合

刚刚单独处理了一下分割线,那一般分割线因人而异,爱好不同,分割线样式也不同。像这种分割线有很多种样式,怎么办呢?有的同学会想到,编写接口,提供多个实现类。对,大致思路是这样,还有一个细节同学们没想到,就是最终需要做一个决策,到底使用哪种分割线样式。这个决策,我们让 controller 自己来确定。

V2 版本

1 package com.gavin.controller;

2

3 import com.gavin.common.SeparatorContext;

4 import com.gavin.service.GenSeparator;

5 import com.gavin.service.impl.BoLangXianSeparator;

6 import org.springframework.beans.factory.annotation.Autowired;

7 import org.springframework.web.bind.annotation.GetMapping;

8 import org.springframework.web.bind.annotation.RestController;

9

10 import javax.annotation.Resource;

11

12 /**
 13

* Created by gavinmiao on 2019/8/30

 14   */

15 @RestController

16 public class DemoV2Controller {

17 @Autowired

18 private SeparatorContext separatorContext;

19 @Resource

20 private GenSeparator boLangXianSeparator;

21 @Resource

22 private GenSeparator greaterThanSeparator;

23 @Resource

24 private GenSeparator hengGangSeparator;

25

26 @GetMapping("/v2/lunch")

27 public String haveLunch(){

28 StringBuilder builder =  new StringBuilder();

29 builder.append("<html>");

30 // 排队
 31 appendStr(builder,getSeparator());

32 appendStr(builder,"(^o^)开始排队(^o^)");

33 appendStr(builder,"1只羊");

34 appendStr(builder,"2只羊");

35 appendStr(builder,"3只羊");

36 appendStr(builder,"4只羊");

37 appendStr(builder,"5只羊");

38 appendStr(builder,"6只羊");

39 appendStr(builder,"7只羊");

40 appendStr(builder,"8只羊");

41 appendStr(builder,"9只羊");

42 appendStr(builder,"(-o-)结束排队(-o-)");

43 // 点菜
 44 appendStr(builder,getSeparator());

45 appendStr(builder,"(^o^)开始点菜(^o^)");

46 appendStr(builder,"蒸羊羔");

47 appendStr(builder,"蒸熊掌");

48 appendStr(builder,"蒸鹿尾儿");

49 appendStr(builder,"烧花鸭");

50 appendStr(builder,"烧雏鸡");

51 appendStr(builder,"烧子鹅");

52 appendStr(builder,"卤猪");

53 appendStr(builder,"卤鸭");

54 appendStr(builder,"酱鸡");

55 appendStr(builder,"腊肉");

56 appendStr(builder,"松花");

57 appendStr(builder,"小肚儿");

58 appendStr(builder,"(-o-)结束点菜(-o-)");

59

60 // 取餐
 61 appendStr(builder,getSeparator());

62 appendStr(builder,"(^o^)开始取餐(^o^)");

63 appendStr(builder,"一盘蒸羊羔");

64 appendStr(builder,"一盘蒸熊掌");

65 appendStr(builder,"一盘蒸鹿尾儿");

66 appendStr(builder,"一盘烧花鸭");

67 appendStr(builder,"一盘烧雏鸡");

68 appendStr(builder,"一盘烧子鹅");

69 appendStr(builder,"一盘卤猪");

70 appendStr(builder,"一盘卤鸭");

71 appendStr(builder,"一盘酱鸡");

72 appendStr(builder,"一盘腊肉");

73 appendStr(builder,"一盘松花");

74 appendStr(builder,"一盘小肚儿");

75 appendStr(builder,"(-o-)结束取餐(-o-)");

76

77 // 用餐
 78 appendStr(builder,getSeparator());

79 appendStr(builder,"(^o^)开始用餐(^o^)");

80 appendStr(builder,"蒸羊羔好吃");

81 appendStr(builder,"蒸熊掌好吃");

82 appendStr(builder,"蒸鹿尾儿好吃");

83 appendStr(builder,"烧花鸭好吃");

84 appendStr(builder,"烧雏鸡好吃");

85 appendStr(builder,"烧子鹅好吃");

86 appendStr(builder,"卤猪好吃");

87 appendStr(builder,"卤鸭好吃");

88 appendStr(builder,"酱鸡好吃");

89 appendStr(builder,"腊肉好吃");

90 appendStr(builder,"松花好吃");

91 appendStr(builder,"小肚儿好吃");

92 appendStr(builder,"(-o-)结束用餐(-o-)");

93 appendStr(builder,getSeparator());

94 builder.append("</html>");

95 return builder.toString();

96 }

97

98 private String getSeparator(){

99 //

return separatorContext.getSeparator(boLangXianSeparator);

100          // return separatorContext.getSeparator(hengGangSeparator);
101 return separatorContext.getSeparator(greaterThanSeparator);

102 }

103

104 private void appendStr(StringBuilder builder,String 啊我额){

105 builder.append(String.format("%s <br/>",啊我额));

106 }

107 }

108

代码运行如下:

编码至高法则-高内聚低耦合

3 个版本我们只是处理了一下整个吃饭过程中的小细节。

真正的吃饭过程的代码还是很长的,得翻好多屏,并且排队、点菜、取餐、用餐, 4 块逻辑,顺序执行,单独某一块比较独立。另一个是,没使用上 MVC 分层思想,应该将业务代码放到业务层中。这样 controller 中的代码就很少了。业务层,我们也可以按业务功能细分一下,针对 controller 中出现的 4 块逻辑,各自创建一个 Service 类。这样就完美的解决了 MVC 问题与代码长的问题了。

最后一个问题,字符串处理属于公共逻辑,可以把它抽取到一个 StringUtil 的公共类中,供 Controller Service 调用。


V3 版本

1 package com.gavin.controller;

2

3 import com.gavin.common.SeparatorContext;

4 import com.gavin.common.StringUtil;

5 import com.gavin.service.*;

6 import org.springframework.beans.factory.annotation.Autowired;

7 import org.springframework.web.bind.annotation.GetMapping;

8 import org.springframework.web.bind.annotation.RestController;

9

10 import javax.annotation.Resource;

11

12 /**
13

* Created by gavinmiao on 2019/8/30

14   */

15 @RestController

16 public class DemoV3Controller {

17 @Autowired

18 private SeparatorContext separatorContext;

19 @Resource

20 private GenSeparator boLangXianSeparator;

21 @Resource

22 private GenSeparator greaterThanSeparator;

23 @Resource

24 private GenSeparator hengGangSeparator;

25

26 @Autowired

27 private OrderService orderService;

28 @Autowired

29 private QueueService queueService;

30 @Autowired

31 private TakeFoodService takeFoodService;

32 @Autowired

33 private HaveDinnerService haveDinnerService;

34

35

36 @GetMapping("/v3/lunch")

37 public String haveLunch(){

38 StringBuilder builder =  new StringBuilder();

39 builder.append("<html>");

40 StringUtil.appendStr(builder,getSeparator());

41 StringUtil.appendStr(builder,queueService.execute());

42 StringUtil.appendStr(builder,getSeparator());

43 StringUtil.appendStr(builder,orderService.execute());

44 StringUtil.appendStr(builder,getSeparator());

45 StringUtil.appendStr(builder,takeFoodService.execute());

46 StringUtil.appendStr(builder,getSeparator());

47 StringUtil.appendStr(builder,haveDinnerService.execute());

48 StringUtil.appendStr(builder,getSeparator());

49 builder.append("</html>");

50 return builder.toString();

51 }

52

53 private String getSeparator(){

54 //

return separatorContext.getSeparator(boLangXianSeparator);

55          // return separatorContext.getSeparator(hengGangSeparator);
56 return separatorContext.getSeparator(greaterThanSeparator);

57 }

58

59

60 }

61

代码运行如下:

编码至高法则-高内聚低耦合

从这 4 个版本中可以感受到,出现拼拼凑凑的感觉时,那么你的代码就是内聚性比较低的表现了。如果代码总要变来变去,其实是耦合高的表现。

最后,想要提高内聚性,可以通过降低耦合度来达到目的。在这儿,我个人提倡同学们编写高内聚、低耦合的代码。

【原创文章,转载请注明出处! GavinMiao】

Gavin

原文  http://www.blogjava.net/GavinMiao/archive/2019/09/11/434613.html
正文到此结束
Loading...