自由飞翔

我在仰望,java之上

统计

留言簿(2)

我关注的blog

阅读排行榜

评论排行榜

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

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

一、javascript

有这样的一个页面,jscss代码都写在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的公共类中,供ControllerService调用。

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

posted on 2019-09-11 15:59 GavinMiao 阅读(202) 评论(0)  编辑  收藏 所属分类: corejavaotherhtml


只有注册用户登录后才能发表评论。


网站导航: