嘻哈说:设计模式之单一职责原则

一、定义

首先呢,咱们来看一下单一职责原则的定义。html

就一个类而言,应该只有一个引发它变化的缘由bash

这个说法不是很好懂,有一些抽象,不过呢,咱们依旧能够尝试着理解一下。app

就一个类而言,只有一个引发它变化的缘由,也就是说,除此以外,不能有其它引发变化的缘由。学习

这样就须要一个前提,这个类只能负责一项职责,而不能负责其余的职责,否则,其余的职责就会存在其余变化的缘由了。优化

通俗的说,即一个类只负责一项职责ui

懒人就比较喜欢这种通俗地定义,一目了然。spa

懒人曾经总结过:通俗的定义,浅显易懂;理论的定义,大脑一懵code

有同感的小伙伴请双击666。htm

二、场景

餐馆聚餐,经过服务员点餐对象

这是一个比较常见的场景,好比懒人撸了五天的代码,身心疲惫,周末的时候呢,就约上三五个好友,去餐馆(番茄餐厅)happy一下(很是单纯的吃饭)。咱们刚刚坐下,就来了一位很漂亮的服务员为咱们点餐。

这样一个服务员为咱们点餐的场景,通常都是什么样的流程?

第一步:客人点餐

懒人:咱呢,不但要吃饱,还要吃好!服务员,先来一份西红柿炒鸡蛋,再来一份酸辣土豆丝!!!

好友:脸呢。。。说好的脸呢。。。

服务员:你是顾客,你是上帝,你说啥就是啥,不过,你刚才说的是啥。。。

第二步:烹饪美食

西红柿炒鸡蛋,先炒鸡蛋,再炒西红柿。。。ok,出锅。

第三步:上餐

服务员:这是您点的西红柿炒鸡蛋,请您慢用。

三、实现

不废话,撸代码。

package com.fanqiekt.principle.single;

/**
* 服务员
* @Author: 番茄课堂-懒人
*/
public class Waiter {

    /**
    * 下单
    * @param dishName 菜名
    */
    public void order(String dishName){
        System.out.println("客人点餐:" + dishName);

        System.out.println("开始烹饪:" + dishName);
        //菜品不一样,作法不一样。
        switch (dishName){
            case "西红柿炒鸡蛋":
                System.out.println("先炒鸡蛋");
                System.out.println("再炒西红柿");
                System.out.println("...");
                break;
            case "酸辣土豆丝":
                System.out.println("先放葱姜蒜");
                System.out.println("再放土豆丝");
                System.out.println("...");
            break;
        }
        System.out.println(dishName + "出锅");

        System.out.println(dishName + "上桌啦,请您品尝");
    }
}
复制代码

服务员这个类比较简单,就一个下单的方法。

为了更好的理解,懒人进行了细节的优化(主要是不少细节懒人压根不了解)。

package com.fanqiekt.principle.single;

/**
 * 客户端
 * @Author: 番茄课堂-懒人
 */
public class Client {
    public static void main(String[] args){
        Waiter waiter = new Waiter();
        waiter.order("西红柿炒鸡蛋");
        System.out.println("-------");
        waiter.order("酸辣土豆丝");
    }
}
复制代码

客户端这个类就至关于客人,客人负责经过服务员点餐。

客人一共点了两道大餐,西红柿炒鸡蛋、酸辣土豆丝,咱们来运行一下,看看结果。

客人点餐:西红柿炒鸡蛋
开始烹饪:西红柿炒鸡蛋
先炒鸡蛋
再炒西红柿
...
西红柿炒鸡蛋出锅
西红柿炒鸡蛋上桌啦,请您品尝
-------
客人点餐:酸辣土豆丝
开始烹饪:酸辣土豆丝
先放葱姜蒜
再放土豆丝
...
酸辣土豆丝出锅
酸辣土豆丝上桌啦,请您品尝
复制代码

OK,两个热气腾腾的饭菜就作好了。

咱们回过头来看一下waiter类,你们以为这个类好很差?

确定是很差了,那...很差在哪里?

这就比如一个小做坊,老板既负责点餐又负责下单,就跟waiter类同样。

咱们通常在小做坊吃饭,感觉会怎么样?

乱,非同通常的杂乱。上菜须要等半天,点餐的时候找不到人。

还有一个弊端,我修改了作饭的流程,会影响下单的业务,增长修改的风险,为何这么说呢?

客人A:老板,给我来一份酸辣土豆丝。

老板:好嘞,您稍等。

懒人:老板,我刚才点的西红柿鸡蛋要少放盐啊。

老板:好的,我放盐的时候用小点的勺子。

客人A:老板,个人菜作了吗?个人同伴都吃完了,没作我就不要了!

老板:您的菜已经作了,立刻就要出锅了。(心里:我勒个去,刚才用小勺放盐的时候把这哥们点的单给忘了,这就尴尬了。。。)

不难看出,当功能冗杂到一个对象中,这样修改就会增长风险。那咱们该如何避免呢?

通常比较完善的餐馆,还至少会有一名厨师。

厨师作饭,服务员点餐,这样作,有什么好处呢?

一来,结构清晰了,各司其职,一目了然。二来,风险下降了,我修改作饭的流程,不会影响下单的业务。

只负责一项职责,这就是单一职责原则。

那咱们尝试着增长一个厨师类。

package com.fanqiekt.principle.single;

/**
 * 厨师
 *
 * @author 番茄课堂-懒人
 */
public class Chef {

    /**
     * 作饭
     * @param dishName 下单的菜名
     */
    public void cooking(String dishName) {
        System.out.println("开始烹饪:"+dishName);
        switch (dishName){
            case "西红柿炒鸡蛋":
                System.out.println("先炒鸡蛋");
                System.out.println("再炒西红柿");
                System.out.println("...");
                break;
            case "酸辣土豆丝":
                System.out.println("先放葱姜蒜");
                System.out.println("再放土豆丝");
                System.out.println("...");
                break;
        }
        System.out.println(dishName + "出锅");
    }
}
复制代码

厨师类,只负责了一项职责:作饭。

这就是类的单一职责原则。

Chef类只有一个cooking方法,cooking方法是根据下单的菜品名称去烹饪不一样的菜,以及炒西红柿鸡蛋以及酸辣土豆丝的具体烹饪过程。这样作合适吗?

不合适的,cooking方法应该只有菜品分发这一项职责,而炒西红柿鸡蛋以及酸辣土豆丝这两件事显然易见与分发没有任何关系,因此拆分出来效果会更好。

咱们将厨师类再优化下。

package com.fanqiekt.principle.single;

/**
 * 厨师
 *
 * @author 番茄课堂-懒人
 */
public class Chef {

    /**
     * 作饭
     * 方法的单一职责原则
     * @param dishName 下单的菜名
     */
    public void cooking(String dishName) {
        System.out.println("开始烹饪:"+dishName);

        switch (dishName){
            case "西红柿炒鸡蛋":
                cookingTomato();
                break;
            case "酸辣土豆丝":
                cookingPotato();
                break;
        }

        System.out.println(dishName + "出锅");
    }

    /**
     * 炒西红柿鸡蛋
     */
    private void cookingTomato() {
        System.out.println("先炒鸡蛋");
        System.out.println("再炒西红柿");
        System.out.println("...");
    }

    /**
     * 炒酸辣土豆丝
     */
    private void cookingPotato() {
        System.out.println("先放葱姜蒜");
        System.out.println("再放土豆丝");
        System.out.println("...");
    }
}
复制代码

优化后Chef类有三个方法。

cooking方法是根据下单的菜品名称去烹饪不一样的菜。

cookingTomato方法是炒西红柿鸡蛋。

cookingPotato方法是炒酸辣土豆丝。

每一个方法只负责一项职责,这就是方法的单一职责原则。

遵照方法单一职责原则的类,是否是更加的直观?修改各自的方法是否是也没有影响到其余的方法?

接下来,咱们再优化下Waiter类,让他遵循类的单一职责原则。

package com.fanqiekt.principle.single;

/**
 * 单一职责原则的服务员
 *
 * @author 番茄课堂-懒人
 */
public class Waiter {
    private Chef chef = new Chef();

    /**
     * 点餐
     * @param dishName 餐名
     */
    public void order(String dishName) {
        System.out.println("客人点餐:"+dishName);

        chef.cooking(dishName);

        System.out.println(dishName+"上桌啦,请您品尝!");
    }
}
复制代码

优化后SingleWaiter类有只负责点餐、上餐这些与服务员相关的职责,而作饭的这些无关的职责则交给了Chef。

遵照类单一职责原则的项目,是否是更加的直观?修改各自的类是否是也没有影响到其余的类?

接下来,咱们把Client运行一下。

客人点餐:西红柿炒鸡蛋
开始烹饪:西红柿炒鸡蛋
先炒鸡蛋
再炒西红柿
...
西红柿炒鸡蛋出锅
西红柿炒鸡蛋上桌啦,请您品尝
-------
客人点餐:酸辣土豆丝
开始烹饪:酸辣土豆丝
先放葱姜蒜
再放土豆丝
...
酸辣土豆丝出锅
酸辣土豆丝上桌啦,请您品尝
复制代码

结果与原来一致。

四、优势

撸过代码后,咱们发现单一职责原则的几个优势。

提升类的可读性

符合单一职责原则的方法、类,结构会更加的清晰,类的可读性也就提升了。

下降类的复杂性 一个类只负责一项职责,一个方法也只负责一项职责。确定要比功能冗杂到一个方法,一个类中要简单得多。

下降风险

修改其中的一个业务,不会影响到业务。

五、总结

咱们必需要意识到,一味的遵照单一职责原则,不停的分拆类所付出的开销是很大的。

这时候就涉及到平衡的问题,平衡单一职责原则与修改形成的开销。

懒人的观点是若是一个方法逻辑不复杂的状况下,能够修改方法实现,不然要拆分为两个方法,遵循方法级别的单一职责原则。

若是一个类方法很少的状况下,能够只增长方法,而不用分拆为多个类,不然要拆分为多个类,遵循类级别的单一职责原则。

六、嘻哈说

接下来,请您欣赏单一职责原则的原创歌曲

嘻哈说:单一职责原则
做曲:懒人
做词:懒人
Rapper:懒人

周末约上了好友去熟悉的餐馆聚餐
只负责点餐的漂亮服务员保持笑容已经成为习惯
只负责作饭的帅气厨师一直待在了烟雾弥漫了几遍的厨房里面
每一个人有本身负责的地盘
就像单一职责
一个类只有一个职责 好体面
它下降了类的复杂性
它提升了类的可读性
那风险被下降表明着单一职责没毛病
复制代码

试听请点击这里

闲来无事听听曲,知识已填脑中去;

学习复习新方式,头戴耳机不小觑。

番茄课堂,学习也要酷。

相关文章
相关标签/搜索