微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

设计模式原则——单一职责原则

单一职责原则(Single Responsibility Principle)

定义一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。即:不要存在多于一个导致类变更的原因。通俗的说,就是一个类只负责一项职责。

问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。

解决方:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。


虽然单一职责原则看起来如此简单,但由于职责扩散,即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。所谓职责扩散,就是因为某种原因,职责P被分化成粒度更细的职责P1和P2。

比如:开始时,类T只负责一个职责P,这符合单一职责原则。后来由于某种原因,需要将职责P细分为粒度更细的职责P1、P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,来分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做将会耗费大量时间和精力,所以,简单地修改类T,用它来负责两个职责是一个比较不错的选择,虽然这违背了单一职责原则。

举例说明,用一个类描述动物吃东西这个场景:

class Animal{
    public void eat(String animal){
       System.out.println(animal+"吃草");
    }
}

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

运行结果:

牛吃草
羊吃草
马吃草

程序上线后,发现问题了,并不是所有的动物都是吃草的,比如狼就是吃肉的。修改时如果遵循单一职责原则,需要将Animal类细分为食草动物Herbivore和肉食性动物Carnivora,代码如下:

class Herbivore{
    public void eat(String animal){
       System.out.println(animal+"吃草");
    }
}

class Carnivora{
    public void eat(String animal){
       System.out.println(animal+"吃肉");
    }
}

public class Client{
    public static void main(String[] args){
       Herbivore herbivore = new Herbivore();
       herbivore.eat("牛");
       herbivore.eat("羊");
       herbivore.eat("马");

       Carnivora carnivora = new Carnivora();
       carnivora.eat("狼");
    }
} 

运行结果:

牛吃草
羊吃草
马吃草
狼吃肉

我们发现这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类Animal来达成目的虽然违背了单一职责原则,但花销却要小的多,代码如下:

class Animal{
	public void eat(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.eat("牛");
		animal.eat("羊");
		animal.eat("马");
		animal.eat("狼");
	}
}

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

class Animal{
	public void eat(String animal){
		System.out.println(animal+"吃草");		
    }

	public void eat2(String animal){
		System.out.println(animal+"吃肉");		
    }
}

public class Client{
	public static void main(String[] args){
		Animal animal = new Animal();
		animal.eat("牛");
		animal.eat("羊");
		animal.eat("马");
		animal.eat2("狼");
	}
}

可以看到,这种修改方式没有改动原来的方法,而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,因为它并没有动原来方法代码

这三种方式各有优缺点,那么在实际编程中,采用哪一种呢?其实这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则。在实际应用中的类都要复杂得多,一旦发生职责扩散而需要修改类时,除非这个类本身非常简单,否则还是遵循单一职责原则的好。


遵循单一职责原则的优点

1、降低类的复杂性,类的职责清晰明确;

2、提高类的可读性和可维护性;

3、变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。


原文:http://www.cnblogs.com/lhws/archive/2012/03/10/2389189.html

原文地址:https://www.jb51.cc/javaschema/283620.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐