1. 개요

이 사용방법(예제)에서는 개체 지향 프로그래밍의 SOLID 원칙 중 하나인 단일 책임 원칙에 대해 설명합니다 .

전반적으로 이 원칙이 무엇인지, 소프트웨어를 설계할 때 이를 구현하는 방법에 대해 자세히 살펴보겠습니다. 또한 이 원칙이 오해의 소지가 있는 경우에 대해 설명합니다.

*SRP = 단일 책임 원칙

2. 단일 책임 원칙

이름에서 알 수 있듯이 이 원칙은 각 클래스가 하나의 책임, 하나의 목적을 가져야 한다고 명시합니다 . 이는 클래스가 하나의 작업만 수행한다는 의미이므로 변경해야 하는 이유는 하나뿐 이어야 한다는 결론을 내리게 됩니다 .

우리는 너무 많이 알고 관련 없는 행동을 하는 객체를 원하지 않습니다. 이러한 클래스는 유지하기가 더 어렵습니다. 예를 들어 여러 가지 이유로 많이 변경하는 클래스가 있는 경우 이 클래스를 더 많은 클래스로 나누어 각각 단일 관심사를 처리해야 합니다. 확실히 오류가 발생하면 찾기가 더 쉬울 것입니다.

어떤 식으로든 텍스트를 변경하는 코드가 포함된 클래스를 생각해 봅시다. 이 클래스의 유일한 작업은 텍스트를 조작하는 것입니다 .

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의 좋은 예는 아닙니다. 여기에서 우리는 두 가지 책임이 있습니다 : 텍스트를 조작하고 인쇄하는 것입니다 .

이 클래스에서 텍스트를 출력하는 메서드를 갖는 것은 단일 책임 원칙을 위반합니다. 이를 위해 텍스트 인쇄만 처리하는 다른 클래스를 만들어야 합니다.

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));
    }
}

이제 이 클래스에서 우리는 우리가 원하는 만큼 다양한 인쇄 텍스트에 대한 메서드를 만들 수 있습니다.

3. 이 원칙은 어떻게 오해의 소지가 있습니까?

소프트웨어에서 SRP를 구현하는 요령은 각 클래스의 책임을 아는 것입니다.

그러나 모든 개발자는 클래스 목적에 대한 비전을 가지고 있어 작업을 까다롭게 만듭니다. 이 원칙을 구현하는 방법에 대한 엄격한 지침이 없기 때문에 책임이 무엇인지에 대한 해석이 남아 있습니다.

이것이 의미하는 바는 애플리케이션의 디자이너인 우리만이 어떤 것이 클래스 범위에 있는지 여부를 결정할 수 있다는 것입니다.

SRP 원칙에 따라 클래스를 작성할 때 문제 도메인, 비즈니스 요구 사항 및 애플리케이션 아키텍처에 대해 생각해야 합니다. 매우 주관적이어서 이 원칙을 구현하는 것이 생각보다 어렵습니다. 이 사용방법(예제)에 있는 예제만큼 간단하지는 않습니다.

이것은 우리를 다음 요점으로 인도합니다.

4. 응집력

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 라는 두 개의 개별 클래스여야 한다는 결론을 내릴 수 있습니다 .

실제로 우리는 거의 항상 함께 사용해야 하는 밀접하게 결합되고 느슨하게 결합된 두 클래스를 얻게 됩니다. 이 세 가지 방법은 서로 다른 작업을 수행할 수 있지만 기본적으로 텍스트 조작이라는 단일 목적을 수행합니다 . 핵심은 지나치게 생각하지 않는 것입니다.

분석법에서 높은 응집력을 달성하는 데 도움이 되는 도구 중 하나는 LCOM입니다. 기본적으로 LCOM은 클래스 구성 요소 간의 연결과 서로 간의 관계를 측정합니다.

Martin Hitz와 Behzad Montazeri는 Sonarqube 한동안 측정했지만 그 이후로 더 이상 사용되지 않는 LCOM4를 도입했습니다.

5. 결론

원칙의 이름은 자명하지만 잘못 구현하기가 얼마나 쉬운지 알 수 있습니다. 프로젝트를 개발할 때 모든 클래스의 책임을 구분하고 응집력에 각별한 주의를 기울이십시오.

항상 그렇듯이 코드는 GitHub에서 사용할 수 있습니다.

Generic footer banner