【转】Java的类和方法的单一职责原则

本文参考自Java设计模式——单一职责模式
Java 设计模式(十) 单一职责原则(SRP)
这个设计模式的核心思想就是降低耦合性,强调一个类/整体只做一件事。这个会很好理解,你只要写一个类,强调一个方法,方法只实现一种功能就行啦!

单一职责模式:就一个类而言,应该仅有一个引起它变化的原因。

有的同学会问,一个类如果只是有且仅有一个因素来引起他的变化,岂不是我们的程序的代码会非常臃肿?这个情况我们要视情况而定,其实在生活中也是,我们如果做到一件事情的专精,那就要舍弃一些其他方面的功能。例如我们的手机可以照相,但是他的专业程度不如数码摄像机,再比如我们的交通工具,汽车负责马路,轮船负责大海,飞机负责天空一样,我们要做到一件事情让他专精一个功能。

在一些特定的情况下,一个类我们只让他承担一个特定的职责,如果一个类承担的职责过多,就等于把这些职责耦合在一起,这是我们编程思想中所忌讳的,程序员一直都再致力于使我们的代码简洁化,我们常说的就是让代码高内聚低耦合,降低代码的耦合性,这样我们在如果对代码中的一个功能模块进行修改时,我们只需要修改特定功能的类即可,从而不会影响其他功能的代码。如果我们提高功能代码的耦合性,那我们设计的代码就会非常脆弱,当一个功能代码发生变化时,我们的代码设计就会招到破坏,影响是非常大的。

我们在实际开发中,会发现软件的功能是非常多的,我们不能盲目的去分离代码和职能,我们一定要去判断这些功能是否需要分离,我们的分离原则就是相同功能的类我们提取使用工厂和策略模式,如果功能不同我们可以让这个类职责单一化,即分离出来。

还有一个就是如果这个类有很多的动机或者因素来改变它,我们就需要考虑分离它,使它的功能单一化。

今天的单一职责模式不太好写代码或者太容易写出代码,我们要根据我们的项目区思考,什么时候会去用到它,什么时候是不需要分离类的。作为一个程序员,我们一定要加入自己的思考,而不只是作为一个代码的搬运工。

因为面向对象的编程是推崇面向接口的编程的,我们对外暴露的方法也最好是以接口的形式定义,再由具体的类进行实现,诸多的好处就不再赘述,我们下面就基于一个简单的场景进行设计,体现单一职责的好处:

场景的定义
比如Pear是一家电子产品商,它要生产pad,phone,watch等设备,但是有一些重复的功能,如果分别设计一套,很显然并不划算,那么接口定义上我们就可以根据功能划分设定单一职责的接口:

接口的定义

//可以拨打电话
interface Callable{
    void call ();
}

//可以触摸控制
interface Touchable{
    void touch();
}

//可以消息提醒
interface MessagePromptable{
    void prompt();
}

//可以接入键盘
interface KeyBoardMatchable{
    void match();
}

实现接口的类依旧单一职责

class StandardCall implements Callable{

    @Override
    public void call() {
        System.out.println("Call to somebody!");
    }
}

class StandardTouch implements Touchable{

    @Override
    public void touch() {
        System.out.println("touch to press the button!");
    }
}

class StandardPromt implements MessagePromptable{

    @Override
    public void prompt() {
        System.out.println(" someone contact to you,sir!");
    }
}

class StandardMatch implements KeyBoardMatchable{

    @Override
    public void match() {
        System.out.println("The keyBoard is ready to work!");
    }
}

产品的生产
我们如果基于我们现有的技术生产一部手机,那么我们需要它能打电话,触屏控制和消息提醒:

//在声明这台手机时我们就明确知道了它的功能
class MyPhone implements Callable,MessagePromptable,Touchable{

    //无需重复研发已有的技术,直接装载即可
    private Callable caller = new StandardCall();
    private MessagePromptable prompter = new StandardPromt();
    private Touchable toucher = new StandardTouch();

    @Override
    public void call() {
        caller.call();
    }

    @Override
    public void prompt() {
        prompter.prompt();
    }

    @Override
    public void touch() {
        toucher.touch();
    }
}

public class SRPTest {
    public static void main ( String [] args ){
        MyPhone phone = new MyPhone();
        phone.call();
        phone.prompt();
        phone.touch();
    }
}

假如我们需要出一款新的手机,但是我们只是拥有了新的呼叫技术,那么只需要在实现这项技术时继承Callable接口,然后在之前手机的Callable的具体是凶案类换成新的技术即可,只需要修改一行代码,是不是感觉棒棒的。职责的单一,对于我们对于现有类的修改造成的影响有了约束
那么如果我想生产一个Pad呢,同理啊,只需要在已有技术上装载即可啊,Pad类依旧只是单一的整合技术形成产品的职责,整合成产品和研发出技术的职责分离,为我们的类的拓展带来了方便

class MyPad implements Touchable,KeyBoardMatchable{

    Touchable toucher = new StandardTouch();
    KeyBoardMatchable matcher = new StandardMatch();

    @Override
    public void match() {
        toucher.touch();
    }

    @Override
    public void touch() {
        matcher.match();
    }
}

总结
通过上面额例子,可以有一个更清晰的理解,其实如果单个接口都提供一个实现类会导致类额数量很庞大,使用起来很不方便,所以我们可以整合一些功能。简而言之:

对于单一职责原则,接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化
下面一个例子,我们的接口依旧单一职责,但是接听和拨打电话的功能往往是不可分的,他们会同时发生变化,所以我们可以提供一个同时继承两个接口的实现类。

class CallAndPrompt implements Callable,MessagePromptable{

    @Override
    public void call() {
        System.out.println("Hello, I have some thing to tell you!");
    }

    @Override
    public void prompt() {
        System.out.println("Hello,what do you want to tell me!");
    }
}

//在声明这台手机时我们就明确知道了它的功能
class MyPhone implements Callable,MessagePromptable,Touchable{

    //无需重复研发已有的技术,直接装载即可
    private Callable caller = new CallAndPrompt();
    //不同的接口调用同一个实现类的不同功能
    private MessagePromptable prompter = (MessagePromptable)caller;
    private Touchable toucher = new StandardTouch();

    @Override
    public void call() {
        caller.call();
    }

    @Override
    public void prompt() {
        prompter.prompt();
    }

    @Override
    public void touch() {
        toucher.touch();
    }
}

从上面的例子,可能你会更理解我的总结。但是原则这个东西要遵守,但是没必要死守。在实际的设计中还是要学会变通。毕竟经典的设计模式也不总是遵守这些设计原则,但他们依旧被广泛地应用到实际当中,而且表现还不错

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值