SOLID原则-单一职责原则

简介

本文我们将讨论面向对象编程中著名的 SOLID 原则之一的单一职责原则。我们将深入讲解什么是单一职责原则和在设计代码时如何实现它,最后将如何避免滥用此设计规则。单一职责的英文表达为 Single Responsibility Principle ,简称 SRP。

单一职责原则详解

就像它的名字的字面意思一样,这个原则表示每个类应该只有一个职责,也就是只有一个目的,一个类只做一样工作,以此可以推断出这个类只有一个原因被修改。我们不想让对象知道的太多以及承担与自己无关的职责,否则,这些类很难维护,例如,一个类由于不同的原因被修改,这个类应该根据职责被拆分为多个类,每个类符合单一职责原则。这样,当错误发生时,可以很容易的找到发生错误的地方。

下面一个类负责用不同的方法来修改文本信息,修改文本信息是它唯一的职责。

public class TextManipulator {
    private String text;
 
    public TextManipulator(String text) {
        this.text = text;
    }
 
    public String getText() {
        return text;
    }
 
    public void appendText(String newText) {
        text = text.concat(newText);
    }
    
    public String findWordAndReplace(String word, String replacementWord) {
        if (text.contains(word)) {
            text = text.replace(word, replacementWord);
        }
        return text;
    }
    
    public String findWordAndDelete(String word) {
        if (text.contains(word)) {
            text = text.replace(word, "");
        }
        return text;
    }
 
    public void printText() {
        System.out.println(textManipulator.getText());
    }
}

虽然这个类看上去没问题,但是对于 SRP 来说,不是一个好的例子,它承担了两个职责,维护和打印文本。
方法 printText 违反了单一职责原则,为了符合此原则,我们需要另外一个类专门用来打印文本,代码如下:

public class TextPrinter {
    TextManipulator textManipulator;
 
    public TextPrinter(TextManipulator textManipulator) {
        this.textManipulator = textManipulator;
    }
 
    public void printText() {
        System.out.println(textManipulator.getText());
    }
 
    public void printOutEachWordOfText() {
        System.out.println(Arrays.toString(textManipulator.getText().split(" ")));
    }
 
    public void printRangeOfCharacters(int startingIndex, int endIndex) {
        System.out.println(textManipulator.getText().substring(startingIndex, endIndex));
    }
}

TextPrinter 专门用来提供各种打印文本的方法,打印是它的唯一职责,符合 SRP。

如何避免误用单一职责原则

在开发过程中使用 SRP 的技巧是理清每个类的职责。然而,每个开发者对每个类的目的都有自己理解,这样增加了使用SRP 的难度,因为没有严格的规则指导我们如何实现 SRP,因此,可能会出现根据每个人不同的理解设计出不同的类实现。这样的实现比较主观,会使实现SRP 比较困难,不像我们上面的例子这么简单。那有没有其他原则来规范我们实现SRP 呢?有的,下面来讲内聚性

内聚性

遵循SRP 原则,我们的类将承担单一职责,类的方法和数据都是和这个职责相关联的,这样的设计从内聚性的角度来看是高内聚的,高内聚和健壮性一起来减少我们程序的出错概率。
当我们的设计基于SRP 时,根本上也符合高内聚特性,高内聚能帮我们为类找到单一职责,反过来,也能帮我们找到某些类承担了过多的职责。
让我们回到类 TextManipulator 的方法定义:

public void appendText(String newText) {
    text = text.concat(newText);
}
 
public String findWordAndReplace(String word, String replacementWord) {
    if (text.contains(word)) {
        text = text.replace(word, replacementWord);
    }
    return text;
}
 
public String findWordAndDelete(String word) {
    if (text.contains(word)) {
        text = text.replace(word, "");
    }
    return text;
}

这里,我们对这个类的职责有一个清晰的描述:文本维护。但是,如果我们不考率内聚性和对类的职责有清晰的定义。我们可以对于文本的更新 操作放在两个类去实现,比如 WriteTextUpdateText。 这样设计的话,事实上,这两个类紧耦合在一起,而且是低内聚,两个类会经常放在一起使用。虽然这三个方法执行不同的操作,但是其目的都是一个:操作文本,这样的话,我们就过度设计了。

总结

虽然这个设计原则从名字来讲它是自解释的,看起来实现也简单,事实上,正确的实现 SRP不是那么容易 , 我们要仔细从职责的角度设计类而且还要额外的关注类的内聚性。

你可能感兴趣的:(面向对象分析和设计,java,面向对象分析和设计)