A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 miaoxiong 于 2019-9-2 15:21 编辑

此法则适合所有语言,咱们以JavaScript和Java两个角度分析一下这个东东。
一、javascript
有这样的一个页面,js、css代码都写在html页面中。
例如:gnj.html
v1版本
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
document.write("高内聚低耦合demo");
</script>
<style>
h1 {
background-color: blueviolet;
}
</style>
<h1>标题</h1>
</body>
</html>


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

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

龙:

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

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

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

优化后的代码,如下:
v2版本

gnj.js

[JavaScript] 纯文本查看 复制代码
document.write("高内聚低耦合demo");


h1.css

[JavaScript] 纯文本查看 复制代码
h1 {
    background-color: blueviolet;
}


gnj_v2.html
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./gnj.js"></script>
    <link rel="stylesheet" type="text/css" href="h1.css"/>
</head>
<body>

    <h1>标题</h1>
</body>
</html>



高内聚:模块内的事。模块内,联系越紧密,内聚性越高。
低耦合:模块间的事,相关的操作,不再直接相互依赖调用

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

v0版本
[Java] 纯文本查看 复制代码
package com.gavin.controller;

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

/**
* Created by 传智播客.黑马程序员.太原校区.苗雄 on 2019\8\30
*/
@RestController
public class DemoController {
    @GetMapping("/lunch")
    public String haveLunch(){
        StringBuilder builder = new StringBuilder();
        builder.append("<html>");
        //排队
        builder.append(String.format("%s <br/>","--------------------------------------------"));
        builder.append(String.format("%s <br/>","(^o^)开始排队(^o^)"));
        builder.append(String.format("%s <br/>","1只羊"));
        builder.append(String.format("%s <br/>","2只羊"));
        builder.append(String.format("%s <br/>","3只羊"));
        builder.append(String.format("%s <br/>","4只羊"));
        builder.append(String.format("%s <br/>","5只羊"));
        builder.append(String.format("%s <br/>","6只羊"));
        builder.append(String.format("%s <br/>","7只羊"));
        builder.append(String.format("%s <br/>","8只羊"));
        builder.append(String.format("%s <br/>","9只羊"));
        builder.append(String.format("%s <br/>","(-o-)结束排队(-o-)"));
        //点菜
        builder.append(String.format("%s <br/>","--------------------------------------------"));
        builder.append(String.format("%s <br/>","(^o^)开始点菜(^o^)"));
        builder.append(String.format("%s <br/>","蒸羊羔"));
        builder.append(String.format("%s <br/>","蒸熊掌"));
        builder.append(String.format("%s <br/>","蒸鹿尾儿"));
        builder.append(String.format("%s <br/>","烧花鸭"));
        builder.append(String.format("%s <br/>","烧雏鸡"));
        builder.append(String.format("%s <br/>","烧子鹅"));
        builder.append(String.format("%s <br/>","卤猪"));
        builder.append(String.format("%s <br/>","卤鸭"));
        builder.append(String.format("%s <br/>","酱鸡"));
        builder.append(String.format("%s <br/>","腊肉"));
        builder.append(String.format("%s <br/>","松花"));
        builder.append(String.format("%s <br/>","小肚儿"));
        builder.append(String.format("%s <br/>","(-o-)结束点菜(-o-)"));

        //取餐
        builder.append(String.format("%s <br/>","--------------------------------------------"));
        builder.append(String.format("%s <br/>","(^o^)开始取餐(^o^)"));
        builder.append(String.format("%s <br/>","一盘蒸羊羔"));
        builder.append(String.format("%s <br/>","一盘蒸熊掌"));
        builder.append(String.format("%s <br/>","一盘蒸鹿尾儿"));
        builder.append(String.format("%s <br/>","一盘烧花鸭"));
        builder.append(String.format("%s <br/>","一盘烧雏鸡"));
        builder.append(String.format("%s <br/>","一盘烧子鹅"));
        builder.append(String.format("%s <br/>","一盘卤猪"));
        builder.append(String.format("%s <br/>","一盘卤鸭"));
        builder.append(String.format("%s <br/>","一盘酱鸡"));
        builder.append(String.format("%s <br/>","一盘腊肉"));
        builder.append(String.format("%s <br/>","一盘松花"));
        builder.append(String.format("%s <br/>","一盘小肚儿"));
        builder.append(String.format("%s <br/>","(-o-)结束取餐(-o-)"));

        //用餐
        builder.append(String.format("%s <br/>","--------------------------------------------"));
        builder.append(String.format("%s <br/>","(^o^)开始用餐(^o^)"));
        builder.append(String.format("%s <br/>","蒸羊羔好吃"));
        builder.append(String.format("%s <br/>","蒸熊掌好吃"));
        builder.append(String.format("%s <br/>","蒸鹿尾儿好吃"));
        builder.append(String.format("%s <br/>","烧花鸭好吃"));
        builder.append(String.format("%s <br/>","烧雏鸡好吃"));
        builder.append(String.format("%s <br/>","烧子鹅好吃"));
        builder.append(String.format("%s <br/>","卤猪好吃"));
        builder.append(String.format("%s <br/>","卤鸭好吃"));
        builder.append(String.format("%s <br/>","酱鸡好吃"));
        builder.append(String.format("%s <br/>","腊肉好吃"));
        builder.append(String.format("%s <br/>","松花好吃"));
        builder.append(String.format("%s <br/>","小肚儿好吃"));
        builder.append(String.format("%s <br/>","(-o-)结束用餐(-o-)"));
        builder.append(String.format("%s <br/>","--------------------------------------------"));
        builder.append("</html>");
        return builder.toString();
    }

}


代码运行如下:



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

[Java] 纯文本查看 复制代码
package com.gavin.controller;

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

/**
* Created by 传智播客.黑马程序员.太原校区.苗雄 on 2019\8\30
*/
@RestController
public class DemoV1Controller {
    @GetMapping("/v1/lunch")
    public String haveLunch(){
        StringBuilder builder = new StringBuilder();
        builder.append("<html>");
        //排队
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始排队(^o^)");
        appendStr(builder,"1只羊");
        appendStr(builder,"2只羊");
        appendStr(builder,"3只羊");
        appendStr(builder,"4只羊");
        appendStr(builder,"5只羊");
        appendStr(builder,"6只羊");
        appendStr(builder,"7只羊");
        appendStr(builder,"8只羊");
        appendStr(builder,"9只羊");
        appendStr(builder,"(-o-)结束排队(-o-)");
        //点菜
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始点菜(^o^)");
        appendStr(builder,"蒸羊羔");
        appendStr(builder,"蒸熊掌");
        appendStr(builder,"蒸鹿尾儿");
        appendStr(builder,"烧花鸭");
        appendStr(builder,"烧雏鸡");
        appendStr(builder,"烧子鹅");
        appendStr(builder,"卤猪");
        appendStr(builder,"卤鸭");
        appendStr(builder,"酱鸡");
        appendStr(builder,"腊肉");
        appendStr(builder,"松花");
        appendStr(builder,"小肚儿");
        appendStr(builder,"(-o-)结束点菜(-o-)");

        //取餐
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始取餐(^o^)");
        appendStr(builder,"一盘蒸羊羔");
        appendStr(builder,"一盘蒸熊掌");
        appendStr(builder,"一盘蒸鹿尾儿");
        appendStr(builder,"一盘烧花鸭");
        appendStr(builder,"一盘烧雏鸡");
        appendStr(builder,"一盘烧子鹅");
        appendStr(builder,"一盘卤猪");
        appendStr(builder,"一盘卤鸭");
        appendStr(builder,"一盘酱鸡");
        appendStr(builder,"一盘腊肉");
        appendStr(builder,"一盘松花");
        appendStr(builder,"一盘小肚儿");
        appendStr(builder,"(-o-)结束取餐(-o-)");

        //用餐
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始用餐(^o^)");
        appendStr(builder,"蒸羊羔好吃");
        appendStr(builder,"蒸熊掌好吃");
        appendStr(builder,"蒸鹿尾儿好吃");
        appendStr(builder,"烧花鸭好吃");
        appendStr(builder,"烧雏鸡好吃");
        appendStr(builder,"烧子鹅好吃");
        appendStr(builder,"卤猪好吃");
        appendStr(builder,"卤鸭好吃");
        appendStr(builder,"酱鸡好吃");
        appendStr(builder,"腊肉好吃");
        appendStr(builder,"松花好吃");
        appendStr(builder,"小肚儿好吃");
        appendStr(builder,"(-o-)结束用餐(-o-)");
        appendStr(builder,getSeparator());
        builder.append("</html>");
        return builder.toString();
    }

    private String getSeparator(){
        return "--------------------------------------------";
    }

    private void appendStr(StringBuilder builder,String 啊我额){
        builder.append(String.format("%s <br/>",啊我额));
    }
}


代码运行如下:


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

[Java] 纯文本查看 复制代码
package com.gavin.controller;

import com.gavin.common.SeparatorContext;
import com.gavin.service.GenSeparator;
import com.gavin.service.impl.BoLangXianSeparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
* Created by 传智播客.黑马程序员.太原校区.苗雄 on 2019\8\30
*/
@RestController
public class DemoV2Controller {
    @Autowired
    private SeparatorContext separatorContext;
    @Resource
    private GenSeparator boLangXianSeparator;
    @Resource
    private GenSeparator greaterThanSeparator;
    @Resource
    private GenSeparator hengGangSeparator;

    @GetMapping("/v2/lunch")
    public String haveLunch(){
        StringBuilder builder = new StringBuilder();
        builder.append("<html>");
        //排队
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始排队(^o^)");
        appendStr(builder,"1只羊");
        appendStr(builder,"2只羊");
        appendStr(builder,"3只羊");
        appendStr(builder,"4只羊");
        appendStr(builder,"5只羊");
        appendStr(builder,"6只羊");
        appendStr(builder,"7只羊");
        appendStr(builder,"8只羊");
        appendStr(builder,"9只羊");
        appendStr(builder,"(-o-)结束排队(-o-)");
        //点菜
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始点菜(^o^)");
        appendStr(builder,"蒸羊羔");
        appendStr(builder,"蒸熊掌");
        appendStr(builder,"蒸鹿尾儿");
        appendStr(builder,"烧花鸭");
        appendStr(builder,"烧雏鸡");
        appendStr(builder,"烧子鹅");
        appendStr(builder,"卤猪");
        appendStr(builder,"卤鸭");
        appendStr(builder,"酱鸡");
        appendStr(builder,"腊肉");
        appendStr(builder,"松花");
        appendStr(builder,"小肚儿");
        appendStr(builder,"(-o-)结束点菜(-o-)");

        //取餐
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始取餐(^o^)");
        appendStr(builder,"一盘蒸羊羔");
        appendStr(builder,"一盘蒸熊掌");
        appendStr(builder,"一盘蒸鹿尾儿");
        appendStr(builder,"一盘烧花鸭");
        appendStr(builder,"一盘烧雏鸡");
        appendStr(builder,"一盘烧子鹅");
        appendStr(builder,"一盘卤猪");
        appendStr(builder,"一盘卤鸭");
        appendStr(builder,"一盘酱鸡");
        appendStr(builder,"一盘腊肉");
        appendStr(builder,"一盘松花");
        appendStr(builder,"一盘小肚儿");
        appendStr(builder,"(-o-)结束取餐(-o-)");

        //用餐
        appendStr(builder,getSeparator());
        appendStr(builder,"(^o^)开始用餐(^o^)");
        appendStr(builder,"蒸羊羔好吃");
        appendStr(builder,"蒸熊掌好吃");
        appendStr(builder,"蒸鹿尾儿好吃");
        appendStr(builder,"烧花鸭好吃");
        appendStr(builder,"烧雏鸡好吃");
        appendStr(builder,"烧子鹅好吃");
        appendStr(builder,"卤猪好吃");
        appendStr(builder,"卤鸭好吃");
        appendStr(builder,"酱鸡好吃");
        appendStr(builder,"腊肉好吃");
        appendStr(builder,"松花好吃");
        appendStr(builder,"小肚儿好吃");
        appendStr(builder,"(-o-)结束用餐(-o-)");
        appendStr(builder,getSeparator());
        builder.append("</html>");
        return builder.toString();
    }

    private String getSeparator(){
        //return separatorContext.getSeparator(boLangXianSeparator);
        //return separatorContext.getSeparator(hengGangSeparator);
        return separatorContext.getSeparator(greaterThanSeparator);
    }

    private void appendStr(StringBuilder builder,String 啊我额){
        builder.append(String.format("%s <br/>",啊我额));
    }
}


代码运行如下:



前3个版本我们只是处理了一下整个吃饭过程中的小细节。
真正的吃饭过程的代码还是很长的,得翻好多屏,并且排队、点菜、取餐、用餐,4块逻辑,顺序执行,单独某一块比较独立。另一个是,没使用上MVC分层思想,应该将业务代码放到业务层中。这样controller中的代码就很少了。业务层,我们也可以按业务功能细分一下,针对controller中出现的4块逻辑,各自创建一个Service类。这样就完美的解决了MVC问题与代码长的问题了。
最后一个问题,字符串处理属于公共逻辑,可以把它抽取到一个StringUtil的公共类中,供Controller和Service调用。
V3版本

[Java] 纯文本查看 复制代码
package com.gavin.controller;

import com.gavin.common.SeparatorContext;
import com.gavin.common.StringUtil;
import com.gavin.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
* Created by 传智播客.黑马程序员.太原校区.苗雄 on 2019\8\30
*/
@RestController
public class DemoV3Controller {
    @Autowired
    private SeparatorContext separatorContext;
    @Resource
    private GenSeparator boLangXianSeparator;
    @Resource
    private GenSeparator greaterThanSeparator;
    @Resource
    private GenSeparator hengGangSeparator;

    @Autowired
    private OrderService orderService;
    @Autowired
    private QueueService queueService;
    @Autowired
    private TakeFoodService takeFoodService;
    @Autowired
    private HaveDinnerService haveDinnerService;


    @GetMapping("/v3/lunch")
    public String haveLunch(){
        StringBuilder builder = new StringBuilder();
        builder.append("<html>");
        StringUtil.appendStr(builder,getSeparator());
        StringUtil.appendStr(builder,queueService.execute());
        StringUtil.appendStr(builder,getSeparator());
        StringUtil.appendStr(builder,orderService.execute());
        StringUtil.appendStr(builder,getSeparator());
        StringUtil.appendStr(builder,takeFoodService.execute());
        StringUtil.appendStr(builder,getSeparator());
        StringUtil.appendStr(builder,haveDinnerService.execute());
        StringUtil.appendStr(builder,getSeparator());
        builder.append("</html>");
        return builder.toString();
    }

    private String getSeparator(){
        //return separatorContext.getSeparator(boLangXianSeparator);
        //return separatorContext.getSeparator(hengGangSeparator);
        return separatorContext.getSeparator(greaterThanSeparator);
    }


}


代码运行如下:


从这4个版本中可以感受到,出现拼拼凑凑的感觉时,那么你的代码就是内聚性比较低的表现了。如果代码总要变来变去,其实是耦合高的表现。
最后,想要提高内聚性,可以通过降低耦合度来达到目的。在这儿,我个人提倡同学们编写高内聚、低耦合的代码。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马