Single Responsibility Principle(단일 책임 원칙)

김정민·2019년 11월 4일
1

참고: 최범균님의 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴.

프로그래밍 경력은 없지만 코딩을 하면서 SRP를 지키는 것은 상당히 어렵다. SRP개념이 와닿지 않을 뿐더러 어디까지가 책임인지 구별이 힘들 때가 있다.하지만 SRP 개념은 객체지향적 코딩의 근간이기 때문에 꼭 알아놓아야 한다.


객체의 존재이유 = 책임이다. 책임이 없다면 필요없는 객체이다.

"클래스는 단 한 개의 책임을 가져야 한다"

가능할까?

위에 말은 "클래스를 변경하는 이유"는 단 한개여야 한다와 일맥상통한다.

생각해보면 당연한 말이다 다양한 이유로 클래스의 코드를 변경해야 한다면 객체의 역할/책임을 잘못 설정해준 것일 수 있다.

한 개의 클래스의 책임이 많아질 수록 절차지향적인 코드일 확률이 높아진다. 왜냐하면 작은 main이 생긴 것과 다름이 없기 때문이다.

예제코드(SRP를 안지킨 코드)

//데이터를 읽는 부분과 데이터를 랜더링 해주는 부분이 혼재되어있다.
public class NoSRPClass {
    public void doSomething() {
        String data = readData();
        renderData(data);
    }
    
    public String readData() {
        return DataSource.readData();
    }
    
    private void renderData(String data) {
        RenderedData renderedData = parseData(data);
        renderedData.render();
    }

    private RenderedData parseData(String data) {
        //파싱 로직
    }
}

//책임이 혼재되어 있을 때 readData()에서 String이 아니라 다른 객체가 나온다 하자

public class NoSRPClass {
    public void doSomething() {
        String[] data = readData();
        renderData(data);
    }

    public String[] readData() {
        return DifferentDataSource.readData();
    }

    private void renderData(String[] data) {
        RenderedData renderedData = parseData(data);
        renderedData.render();
    }

    private RenderedData parseData(String[] data) {
        //파싱 로직
    }
}
//책임이 혼재되어 있기 때문에 데이터를 읽는 부분이 String에서 String[] 바뀌자 데이터를 Render하는 부분도 바뀌었다.
//즉, " 클래스를 변경하는 이유는 단 하나여야한다"를 위반한다. 데이터 읽기 로직이 바뀌니 데이터 렌더링 로직이 바뀌었다, SRP를 어겼다.

SRP를 지킨코드

public class SRPDataReader {
    public Data readData() {
        return new Data(DataSource.readData());
    }

}

public class SRPDataRenderer {
    public void render(Data data) {
        //랜더링 로직
        data.render();
    }
}

public class SRPClient {
    public void doSomething() {
        Data data = srpDataReader.readData();
        srpDataRenderer.render(data);
    }
}
//코드를 이렇게 짠다면 SRPDataReader코드가 바뀌어도 SRPDataRenderer코드는 바뀌는 않는다
//즉, SRP를 지킨것이다 (가능했던 이유 return 값 추상화, 객체나누기!)

예제에서 봤듯이 각각의 책임은 서로 다른 이유로 변경되고, 서로 다른 비율로 변경되어야 한다. SRP를 안지킨코드에서는 데이터를 읽는 로직과 데이터를 보여주는 로직이 함께 있다 보니까 변경이유가 여러개고 변경이 일어났을 때 다른 코드에도 영향을 준다.

하지만 객체를 나눈다면 두 코드의 결합도는 낮아진다!

profile
장인정신을 갖는 개발자고 성장하고 싶습니다.

0개의 댓글