单一职责原则(Single Responsibility Principle)
SRP 基本概念
单一职责原则
- 定义:应该有且仅有一个原因引起类的变更,也就是接口或类和职责的关系是一一对应的。
- 难点:职责的划分:
- 在不同情景和生产环境下我们对职责的细化是不同的(职责单一的相对性)
- 单一职责原则提出的是一个评价接口是否优良的标准,但是职责和变化原因是不可度量的,因项目而异,因环境而异(不可度量性)
- 优势:
- 类的复杂性降低:每个类或接口都只实现单一的职责,定义明确清晰
- 可读性提高:定义明确清晰,自然带来较高的代码可读性
- 可维护性提高:代码可读性强,更容易理解,自然方便维护,而且职责单一所以类之间耦合度较低,所以更容易修改。
- 拓展性更好:有新的职责需要拓展,只需要继承对应的接口实现新的实现即可。
例讲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();
}
}
从上面的例子,可能你会更理解我的总结。但是原则这个东西要遵守,但是没必要死守。在实际的设计中还是要学会变通。毕竟经典的设计模式也不总是遵守这些设计原则,但他们依旧被广泛地应用到实际当中,而且表现还不错
时间: 2024-10-10 23:13:03