TIL | [CS] SOLID - 객체지향 설계 5원칙

hyemin·2022년 4월 13일
1

CS

목록 보기
4/5
post-thumbnail

객체지향 설계를 할 때 지키면 좋겠다는 기본 원칙 5가지의 앞글자를 따서 SOLID라고 부른다.

  • SRP(Single Responsibility Principle) : 단일 책임 원칙
  • OCP(Open Closed principle) : 개방 폐쇄 원칙
  • LSP(Liskov Substitution principle) : 리스코프 치환 원칙
  • ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
  • DIP(Dependency inversion principle) : 의존관계 역전 원칙

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

모든 클래스는 하나의 책임만 가져야 한다

  • 책임이라는 단어의 뜻이 모호한데, 어떤 기능에 문제가 생겼을 때 어떤 특정 모듈(패캐지, 클래스, 메소드) 때문이라고 지목할 수 있다면 단일 책임 원칙을 잘 따른 것이라고 볼 수 있다.

  • SRP를 잘 지켰다면, 응집도는 높이고 결합도를 낮춰 유지보수가 용이해진다

단일 책임 원칙 위배 예시

public class Hyemco {
	public static void main(String[] args) {
        coding();
        posting();
        youtube();
        cleaning();
        laundering();
        calling();
        gift();
    }
}

단일 책임 원칙 만족 예시
공통점을 가진 "Person" 클래스를 extends하여 책임에 따라 하위 클래스로 분류한다..

pacakage srp;

public class Person {
	youtube();
}
pacakage srp;

public class JopSeeker extends Person {
	coding();
    posting();
}
pacakage srp;

public class Daughter extends Person {
	cleaning();
    laundering();
}

2. 개방 폐쇄 원칙 : OCP(Open Closed principle)

SW 요소는 확장에 대해서는 열려있고 수정에 대해서는 닫혀있어야 한다

  • 확장에 대해 열려있다
    : 새로운 기능을 확장하기 위해 기존 코드를 손대지 않고 새로운 코드를 추가하는 것만으로 가능해야 함
  • 수정에 대해 닫혀있다
    : 새로 추가/수정되는 코드는 기존 코드의 변경을 초래하지 않음


3. 리스코프 치환 원칙 : LSP (Liskov Substitution principle)

상위 타입의 객체를 하위 타입의 객체로 치환해도 상위타입을 사용하는 프로그램은 정상적으로 동작해야 한다

쉽게 말하자면, 자식 클래스는 최소한 부모 클래스에서 수행한 기능은 수행할 수 있어야 된다는 뜻으로 부모 클래스와 자식 클래스 사이는 행위가 일관되어야 한다

  • 커피를 만들 수 있는 부모 Sam의 자식 Enden도 커피를 만드는 기능을 수행할 수 있어야 한다

리스코프 치환 원칙 위배 예시

리스코프 치환 원칙 만족 예시


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

특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다

  • 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙

인터페이스란?
인터페이스로 구현된 클래스를 동일한 기능을 수행하도록 강제하는 것

인터페이스 분리 원칙 위배 예시

interface MultifunctinPrinter {
	public void copy();

    public void print();

    public void fax();
}

Fax 클래스가 복합기 인터페이스를 implements 했기에 copy(), print(), fax() 3 메소드를 다 Override한다

public class Fax implements MultifunctinPrinter{

    @Override
    public void copy() { 
    }

    @Override
    public void print() {
    }

    @Override
    public void fax() {
    }
}

그러나 Fax 클래스에서 fax()의 기능만 필요할 수도 있다. fax() 기능만 이용하는 클라이언트가 print() 기능의 변경으로 인해 발생하는 문제에 영향을 받지 않도록 해야한다

인터페이스 분리 원칙 만족 예시

interface Fax {
    public void fax();
}
public class Fax implements Fax{
    @Override
    public void fax() {
    }
}
interface Print {
    public void print();
}
public class Print implements Print{
    @Override
    public void print() {
    }
}

5. 의존관계 역전 원칙 : DIP(Dependency inversion principle)

상위 모듈이 하위 모듈에 의존해서는 안된다. 두 모듈 모두 추상화에 의존해야 한다

  • 의존 관계를 맺을 때 변화하기 쉬운 것에 의존하기보다는 변화하기 어려운 것/변화하지 않는 것에 의존하라는 뜻

의존관계 역전 원칙 위배 예시

class Carrot {
	 public String toString() {
        return "Carrot";
    }
}
public class Rabbit {
	private Carrot carrot;
    
   	public void setCarrot(Carrot carrot) {
    	this.carrot = carrot;
    }
    
    public void eat() {
        System.out.println(carrot.toString());
    }
}

토끼는 Carrot 클래스에 의존하고 있는데, 만약 토끼가 Carrot이 아니라 Apple로 먹이를 바꾼다면 코드에 상당한 변화가 필요하게 된다

의존관계 역전 원칙 만족 예시
위의 문제를 해결하기 위해 의존관계를 역전시켜 Carrot과 Apple을 추상적인 Vegetable이라는 상위 클래스를 상속받게 하고 토끼는 Vegetable 클래스에 의존하게 만들어 줘야한다

public class Carrot extends Vegetable {
    public String toString() {
        return "Carrot";
    }
}
public class Apple extends Vegetable {
    public String toString() {
        return "Apple";
    }
}
public class Main {
    public static void main(String[] args) {
    	// 먹이가 Carrot일 경우
        Vegetable v = new Carrot();
        Rabbit r = new Rabbit();
        r.setVegetable(v);
        r.eat();
        
        // 먹이가 Apple일 경우
        Vegetable v = new Apple();
        Rabbit r = new Rabbit();
        r.setVegetable(v);
        r.eat();       
    }
}

요약

SOLID - 객체 지향을 할 때 지켜야 하는 5대 원칙

  1. 단일 책임 원칙(SRP)
    : 모든 클래스는 각각 하나의 책임을 가져야한다

  2. 개방 폐쇄의 원칙(OCP)
    : 기능을 추가할 때는 기존의 코드를 수정하지 않고도 추가할 수 있어야한다

  3. 리스코프 치환 원칙(LSP)
    : 자식 클래스는 부모클래스를 대체할 수 있도록 상속해야한다

  4. 인터페이스 분리 원칙(ISP)
    : 하나의 범용적인 인터페이스보다는 여러개의 구체적인 인터페이스를 사용해야한다

  5. 의존관계 역전 원칙(DIP)
    : 의존 관계를 쓸 떄는 추성화된 것(상위 클래스)에 의존해야한다

0개의 댓글