设计模式六大原则—— 单一职责原则(SRP,Single Responsibility Principle)

转自 http://baike.baidu.com/item/%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99
转自 http://blog.csdn.net/zhengzhb/article/details/7278174

简介

单一职责原则(SRP,Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特·C·马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。马丁表示此原则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著作中的内聚性原则发展出的。

所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。

原理

如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性。

问题由来

之所以会出现单一职责原则就是因为在软件设计时会出现以下类似场景:

T本来只负责一个职责P,但由于职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说职责P1和P2被耦合在了一起。

解决办法

遵守单一职责原则,将当将不同的职责封装到不同的类或模块中。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

举例说明

用一个类描述动物呼吸这个场景:

class Animal{  
    public void breathe(String animal){  
        System.out.println(animal+"呼吸空气");  
    }  
}  
public class Client{  
    public static void main(String[] args){  
        Animal animal = new Animal();  
        animal.breathe("牛");  
        animal.breathe("羊");  
        animal.breathe("猪");  
    }  
}

运行结果:

牛呼吸空气
羊呼吸空气
猪呼吸空气

程序上线后,发现问题了,并不是所有的动物都呼吸空气的,比如鱼就是呼吸水的。

遵循单一职责原则的修改方案

修改时如果遵循单一职责原则,需要将Animal类细分为陆生动物类Terrestrial,水生动物Aquatic,代码如下:

class Terrestrial{  
    public void breathe(String animal){  
        System.out.println(animal+"呼吸空气");  
    }  
}  
class Aquatic{  
    public void breathe(String animal){  
        System.out.println(animal+"呼吸水");  
    }  
}  

public class Client{  
    public static void main(String[] args){  
        Terrestrial terrestrial = new Terrestrial();  
        terrestrial.breathe("牛");  
        terrestrial.breathe("羊");  
        terrestrial.breathe("猪");  

        Aquatic aquatic = new Aquatic();  
        aquatic.breathe("鱼");  
    }  
}  

运行结果:

牛呼吸空气
羊呼吸空气
猪呼吸空气
鱼呼吸水

我们会发现如果这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。

违背了单一职责原则,但改动最小的方案

而直接修改类Animal来达成目的虽然违背了单一职责原则,但花销却小的多,代码如下:

class Animal{  
    public void breathe(String animal){  
        if("鱼".equals(animal)){  
            System.out.println(animal+"呼吸水");  
        }else{  
            System.out.println(animal+"呼吸空气");  
        }  
    }  
}  

public class Client{  
    public static void main(String[] args){  
        Animal animal = new Animal();  
        animal.breathe("牛");  
        animal.breathe("羊");  
        animal.breathe("猪");  
        animal.breathe("鱼");  
    }  
}  

可以看到,这种修改方式要简单的多。但是却存在着隐患:有一天需要将鱼分为呼吸淡水的鱼和呼吸海水的鱼,则又需要修改Animal类的breathe方法,而对原有代码的修改会对调用“猪”“牛”“羊”等相关功能带来风险,也许某一天你会发现程序运行的结果变为“牛呼吸水”了。这种修改方式直接在代码级别上违背了单一职责原则,虽然修改起来最简单,但隐患却是最大的。还有一种修改方式:

在类级别上违背单一职责,但方法级别上却是符合的方案

class Animal{  
    public void breathe(String animal){  
        System.out.println(animal+"呼吸空气");  
    }  

    public void breathe2(String animal){  
        System.out.println(animal+"呼吸水");  
    }  
}  

public class Client{  
    public static void main(String[] args){  
        Animal animal = new Animal();  
        animal.breathe("牛");  
        animal.breathe("羊");  
        animal.breathe("猪");  
        animal.breathe2("鱼");  
    }  
}  

可以看到,这种修改方式没有改动原来的方法,而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,因为它并没有动原来方法的代码。这三种方式各有优缺点,那么在实际编程中,采用哪一中呢?其实这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则。

例如本文所举的这个例子,它太简单了,它只有一个方法,所以,无论是在代码级别上违反单一职责原则,还是在方法级别上违反,都不会造成太大的影响。实际应用中的类都要复杂的多,一旦发生职责扩散而需要修改类时,除非这个类本身非常简单,否则还是遵循单一职责原则的好。

遵循单一职责原的优点

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

相关知识

单一职责原则并不是一个孤立的面向对象设计原则,它是面向对象设计五个基本原则(SOLID)之一。这些原则是:单一职责原则、开闭原则、接口隔离原则、里氏替换原则和依赖倒置原则。这些原则被一起应用时可以使一个软件系统更易被维护和扩展。这些原则被典型的应用在测试驱动开发上,并且是敏捷开发以及自适应软件开发等指导思想的重要组成部分。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript设计模式通常包括以下六大原则: 1. 单一职责原则Single Responsibility PrincipleSRP):一个对象(函数、类等)只应负责一个单一的职责或功能。这使得对象的设计更加简单、清晰,并提高了代码的可维护性和可复用性。 2. 开放封闭原则(Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。即通过扩展已有的代码来实现新的功能,而不是直接修改已有的代码。这样可以保持代码的稳定性和可靠性。 3. 里氏替换原则(Liskov Substitution Principle,LSP):子类对象应该能够替换父类对象,而程序的行为不会发生变化。即在使用父类对象的地方,可以替换成子类对象而不会影响程序的正确性。 4. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块(抽象)不应该依赖于底层模块(具体),而是应该依赖于抽象。具体来说,将抽象与具体的实现分离,通过依赖注入的方式来实现高层模块对底层模块的使用。 5. 接口隔离原则(Interface Segregation Principle,ISP):客户端不应该强迫依赖它不需要的接口。接口应该小而精简,不应该包含多余的方法。这样可以避免接口的臃肿和不必要的依赖。 6. 迪米特原则(Law of Demeter,LoD):一个对象应该对其他对象有尽可能少的了解,只与其直接的朋友交流。换句话说,应该尽量减少对象之间的耦合关系,降低代码的复杂性和维护成本。 这些设计原则是指导软件设计的准则,它们可以帮助我们编写出高质量、易维护并且可扩展的JavaScript代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值