객체지향 5원칙(SOLID) - 단일 책임 원칙

2022. 2. 15. 14:02PHP

객체지향 5원칙

올바른 객체지향 설계를 위해 수립한 원칙이 있으며, 이 다섯 가지의 원칙을 통틀어 객체지향 5원칙(SOLID)이라 명명한다. 필수로 적용하지 않지만, 적어도 이 규칙을 준수하면 준수할 수록 올바르게 설계된 객체지향이라 할 수 있습니다.

 

이 다섯 가지 원칙은 아래와 같습니다.

1. 단일 책임 원칙 (Single Responsibility Principle)

2. 개방-폐쇄 원칙 (Open-Closed Principle)

3. 리스코프 치환 원칙 (Liskov Substitution Principle)

4. 인터페이스 분리 원칙 (Interface Segregation Principle)

5. 의존성 역전 원칙 (Dependency Inversion Principle)

 

각 원칙의 영어 앞글자를 따서 SOLID원칙이라고 합니다.

 

단일 책임 원칙 (Single Responsibility Principle)

단일 책임 원칙이란 하나의 객체는 반드시 하나의 동작만의 책임을 갖는다는 원칙입니다.

사용 이유는 객체가 담당하는 동작. 즉, 책임이 많아질 수록 해당 객체의 변경에 따른 영향도의 양과 범위가 매우 커집니다. 단일 책임 원칙은 특정 객체의 책임 의존성 과중을 지양하기 위한 원칙입니다.

 

간단한 코드로 예시를 구현해보겠습니다.(PHP)

자동차는 휠의 구동 특성에 따라 전륜(FWD), 후륜(RWD), 사륜(AWD)로 나뉘며, 그 특성은 아래와 같습니다.

  • 전륜 구동인 경우 앞의 두 바퀴에만 동력을 전달한다.
  • 후륜 구동인 겨우 뒤의 두 바퀴에만 동력을 전달한다.
  • 사륜 구동인 경우 전체 바퀴에 동력을 전달한다.

단일 책임 원칙을 지키지 않은 코드

class Car{
    protected $WD;
    protected $WHEEL = array(0,1,2,3);
    public function __construct($wd){
        return $this -> WD = $wd;
    }
    /**
     * 주행 함수
     *
     * @param power: [int] 동력
     */
    public function run($power){
        $title = strtoupper($this -> WD);
        if($title == "FWD"){
            $this -> WHEEL[0] = $power;
            $this -> WHEEL[1] = $power;
        }else if($title == "RWD"){
            $this -> WHEEL[3] = $power;
            $this -> WHEEL[4] = $power;
        }else if($title == "AWD"){
            $this -> WHEEL[0] = $power;
            $this -> WHEEL[1] = $power;
            $this -> WHEEL[3] = $power;
            $this -> WHEEL[4] = $power;
        }
        echo("휠 동력 상태: ".$this -> WHEEL[0].", ".$this -> WHEEL[1].", ".$this -> WHEEL[2].", ".$this -> WHEEL[3]);
    }
};
$A = new Car('FWD');
$A.run(777); // 휠 동력 상태: 777,777,2,3 출력

 

위의 코드를 단일 책임 원칙을 지키는 코드로 변경해보겠습니다.

abstract class Car{
    protected $WD;
    protected $WHEEL = array(0,1,2,3);
    public function __construct($wd){
        return $this -> WD = $wd;
    }

    //추상 메소드는 기능 구현이 불가능하고 일반 클래스에서 기능을 구현
    abstract function run($power);
}
/**
 * 전륜차 객체
 *
 * @author RWB
 * @since 2021.08.13 Fri 01:03:13
 */
class FrontWheelCar extends Car{
    public function __construct($wd){
        parent::__construct($wd);
    }
    public function run($power){
        $this -> WHEEL[0] = $power;
        $this -> WHEEL[1] = $power;
        echo("전륜차 객체<br>");
        echo("휠 동력 상태: ".$this -> WHEEL[0].", ".$this -> WHEEL[1].", ".$this -> WHEEL[2].", ".$this -> WHEEL[3]."<br><br>");
    }
}
$A = new FrontWheelCar();
$A->run(111);

/**
 * 후륜차 객체
 *
 * @author RWB
 * @since 2021.08.13 Fri 01:03:13
 */
class RearWheelCar extends Car{
    public function __construct($wd){
        parent::__construct($wd);
    }
    public function run($power){
        $this -> WHEEL[2] = $power;
        $this -> WHEEL[3] = $power;
        echo("후륜차 객체<br>");
        echo("휠 동력 상태: ".$this -> WHEEL[0].", ".$this -> WHEEL[1].", ".$this -> WHEEL[2].", ".$this -> WHEEL[3]."<br><br>");
    }
};
$B = new RearWheelCar();
$B->run(222);
/**
 * 사륜차 객체
 *
 * @author RWB
 * @since 2021.08.13 Fri 01:03:13
 */
class AllWheelCar extends Car{
    public function __construct($wd){
        parent::__construct($wd);
    }
    public function run($power){
        $this -> WHEEL[0] = $power;
        $this -> WHEEL[1] = $power;
        $this -> WHEEL[2] = $power;
        $this -> WHEEL[3] = $power;
        echo("사륜차 객체<br>");
        echo("휠 동력 상태: ".$this -> WHEEL[0].", ".$this -> WHEEL[1].", ".$this -> WHEEL[2].", ".$this -> WHEEL[3]);
    }
}
$C = new AllWheelCar();
$C->run(333);

결과는
전륜차 객체
휠 동력 상태: 111, 111, 2, 3

후륜차 객체
휠 동력 상태: 0, 1, 222, 222

사륜차 객체
휠 동력 상태: 333, 333, 333, 333

 

요약

전륜,후륜,사륜에 해당하는 객체를 생성한다. 이 세 객체는 모두 Car 클래스에 포함되므로 Car를 상속받아 구현했습니다.

각 객체의 run() 메소드에 동작을 구현함으로써, 각각의 객체가 하나의 책임을 가지게 됩니다.

 

이렇게 객체별로 책임을 나누면, 코드 변경 시에도 해당하는 객체만 수정하면 되므로, 의존성이 낮아져 올바른 모듈화를 구현할 수 있습니다. 그 뿐만 아니라 코드가 간결해져 요지보수가 쉬워질 뿐만 아니라 수정에 따른 영향도도 매우 작아집니다.

 

참고자료

자바를 예시로 든 자료 https://blog.itcode.dev/posts/2021/08/13/single-responsibility-principle#%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-5%EC%9B%90%EC%B9%99