[JAVA] 객체지향 개발 SOLID

buckshot·2024년 5월 2일

JAVA

목록 보기
3/18
post-thumbnail

S - Single Responsibility Principle (단일 책임 원칙)

하나의 클래스는 하나의 책임만을 갖고 있어야 한다는 원칙이다.
즉, 클래스를 변경하는 이유는 하나를 가져야 한다. 이를 통해 클래스가 변경이 되어도 다른 기능에 미치는 영향을 최소화할 수 있다.

Report라는 클래스가 있고 해당 클래스는 보고서를 출력하고 저장하는 두가지 책임을 갖고 있다고 하자

class Report {
	void printReport() {
    // 출력 로직
    }
    
    void saveToFile(String fileName) {
    // 저장 로직
    }
}

단일 원칙에 따라 두가지 책임을 갖고있기 때문에 하나의 클래스는 하나의 책임만 갖도록 수정

class Report {
	void printReport() {
    // 출력 로직
    }
}

class ReportSaver {   
    void saveToFile(String fileName, Report report) {
    // 저장 로직
    }
}

O - Open/Closed Principle (개방/폐쇄 원칙)

소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하며, 변경에 있어서는 반대로 닫혀 있어야 한다. 이를 위해 추상화와 상속 등의 개냠을 활용할 수 있다.

abstract class Shap{
	abstract void draw();
}

class Circle extends Shape {
	void draw() {
    	System.out.println("원 그리기");
    }
}

class Squara extends Shape {
	void draw() {
    	System.out.println("정사각형 그리기");
    }
}

class ShapeDrawer {
	void draw(Shape shape) {
    	shape.draw();
    }
}

ShapeDrawer 클래스는 확장에 열려있고, 변경에는 닫혀있다.
새로운 Shape 유형이 추가 되더라도 ShapeDrawer 클래스를 수정할 필요가 없다.

L - Liskov Substitution Principle (리스코프 치환 원칙)

하위 타입의 객체는 상위 타입의 객체를 대체할 수 있어야 한다는 원칙이다.
상위 클래스의 객체를 하위 클래스 객체로 대체하여도 시스템의 동작에 영향을 미치지 않아야 한다.
이 원칙은 상속 구조의 올바른 사용을 보장한다.

class Bird {
	void fly() {
    	System.out.println("새가 날다");
    }
}

class Ostrich extends Brid {
	void fly() {
    	throw new UnsupportedOperationException();
    }
}

타조 클래스는 새의 하위 클래스다. 그러나 타조 클래스는 fly 메소드를 지원하지 않으므로, 새 타입을 타조로 대체하는 경우는 리스코프 치환의 원칙에 위배가 된다.

I - Interface Segregation Principle (인터페이스 분리 원칙)

사용하지 않는 인터페이스는 구현하지 않아야 한다는 원칙이다.
인터페이스를 작고 구체적으로 유지하여 클라이언트가 자신이 사용하지 않는 메소드에 의존하지 않도록 해야한다.

interface Worker {
    void work();
    void eat();
}

class HumanWorker implements Worker {
    public void work() {
        // 작업 수행
    }
    
    public void eat() {
        // 식사 수행
    }
}

class RobotWorker implements Worker {
    public void work() {
        // 작업 수행
    }
    
    public void eat() {
        // 로봇은 식사가 필요 없으므로, 이 메소드 구현은 부적합
    }
}

Worker 인터페이스는 work와 eat 메소드 두가지를 갖고 있다. 그러나 RobotWorker는 eat을 구현할 필요가 없다.
이는 인터페이스만 구현하도록 할 수 있다.

D - Dependency Inversion Principle (의존성 역전 원칙)

고수준 모듈은 저수준 모듈에 의존해서는 안되며, 둘 다 추상화에 의존해야 한다는 원칙
추상화는 세부사항에 의존해서는 안되며, 세부 사항이 추상화에 의존을 해야한다. 이 원칙을 통하여 의존성 방향을 역전시켜 변경에 더 유연하게 대응이 가능하다.

interface Switchable {
    void turnOn();
    void turnOff();
}

class LightBulb implements Switchable {
    public void turnOn() {
        System.out.println("전구를 켭니다");
    }
    
    public void turnOff() {
        System.out.println("전구를 끕니다");
    }
}

class Switch {
    private Switchable device;
    
    public Switch(Switchable device) {
        this.device = device;
    }
    
    void toggle() {
        // 토글 로직
        // device 상태를 변경
    }
}

Switch 클래스는 Switchable 인터페이스를 통해 LightBuld 클래스에 의존한다.
이는 고수준 모듈 (Switch)과 저수준 모듈 (LightBulb)사이의 직접적인 의존 관계를 제거하며, Switch클래스를 다양한 Switchable 구현체에 대해 사용할 수 있게 하여 의존선을 역전 원칙에 따른다.

profile
let's go insane

0개의 댓글