[객체 지향 프로그래밍] SOLID

무1민·2023년 11월 27일
1

객체 지향

목록 보기
2/2
post-thumbnail

전 시간에 객체 지향 프로그래밍에 대해서 알아보다가 Service와 ServiceImpl의 관계에 대해서 알아보는 시간을 가졌었다.
다시 돌아와서 객체 지향 프로그래밍의 SOLID 법칙에 대해서 다시 알아보도록 하겠다.

🎶SOLID?

객체 지향 설계에는 다섯가지 원칙이 있다.

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

👩‍💼SRP - 단일 책임 원칙

한 클래스는 하나의 책임만 가져야 한다.
하나의 책임이라는 말은 모호하다. 중요한 기준은 변경이다.
변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이다.
SRP 원칙을 적용하면 다른 클래스들이 서로 영향을 미치는 연쇄작용을 줄일 수 있따.
즉, 응집도는 높이고 결합도는 낮출 수 있다.

위의 남자 클래스에는 역할 책임이 너무 많다. SRP를 적용시키면, 다음과 같이 분리할 수 있다.

코드의 가독성 향상, 유지보수 용이 라는 이점을 가질 수 있다.


다른 예시를 보면, 다음과 같다

class 강아지 {
    final static Boolean 수컷 = true;
    final static Boolean 암컷 = false;
    Boolean 성별;
    void 소변보다() {
        if (this.성별 == 수컷) {
            // 한쪽 다리를 들고 소변을 보다.
        } else {
            // 뒷다리 두 개를 굽혀 앉은 자세로 소변을 본다.
        }
    }   
}

위의 코드에선 소변보다() 메소드에서 수컷, 암컷 모두 구현하려고 해서 단일 책임 원칙을 위반하고 있다.

abstract class 강아지 {
    abstract void 소변보다();
}
class 수컷강아지 extends 강아지 {
    void 소변보다() {
        // 한쪽 다리를 들고 소변을 본다.
    }
}
class 암컷강아지 extends 강아지 {
    void 소변보다() {
        // 뒷다리 두 개로 앉은 자세로 소변을 본다.
    }
}

그래서 위와 같이 강아지라는 추상 클래스를 두고 수컷, 암컷 클래스가 각자 자신의 특징에 맞게 소변보다() 메소드를 구현해서 사용하는 것으로 리팩터링할 수 있다.
또한, 우리가 spring에서 도메인, repository, service별로 나눠 놓은게 SRP법칙을 지킨 것이라고 할 수 있다.

// 단일 책임 원칙에 맞는 클래스
class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    // 사용자 관련 메소드들
}
class UserRepository {
    public void save(User user) {
        // 데이터베이스에 사용자 저장
    }
}

💆‍♀️OCP - 개방 폐쇄 원칙

소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 한다.
요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야하며 쉽게 확장이 가능하여 재사용할 수 있어야 한다.
OCP를 가능케 하는 중요한 메커니즘은 추상화다형성이다.
OCP는 객체지향의 장점을 극대화하는 아주 중요한 원리이다.

위의 운전자 클래스는 마티즈 클래스와 소나타 클래스의 변화에 따라 행동이 의존적으로 변하게 된다.
따라서 자동차들 클래스 위에 자동차라는 상위 클래스를 두면 운전자는 마티즈와 소나타 클래스의 변경사항에 영향받지 않을 수 있다.

JDBC가 OCP의 가장 좋은 예다. MySQL에서 오라클로 바뀌더라도 Connection을 설정하는 부분만 변경해주면 된다.
즉, 자바 어플리케이션은 데이터베이스라고 하는 주변의 변화에 닫혀 있는 것이다.
Car 클래스는 아니지만 같은 종류의 자바 예시를 들어보겠다.

// 개방/폐쇄 원칙에 맞는 클래스
abstract class Report {
    public abstract void generateReport();
}
class PDFReport extends Report {
    public void generateReport() {
        // PDF 형식의 보고서 생성
    }
}
class ExcelReport extends Report {
    public void generateReport() {
        // Excel 형식의 보고서 생성
    }
}

🤷‍♂️LSP - 리스코프 치환 원칙

서브 타입은 언제나 자신의 기반 타입으로 변경할 수 있어야 한다.
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다. 다형성을 지원하기 위한 원칙이며, 인터페이스를 구현한 구현체는 믿고 사용하려면 이 원칙이 필요하다.
상속을 잘 활용하고 있다면, 이미 LSP는 잘 구현하고 있는 것이다.

서브 클래스는 상위 클래스의 기능을 이용할 수 있어야 한다.

// 리스코프 치환 원칙에 맞는 클래스
class Bird {
    public void eat() {
        // 먹는 행위
    }
}
class FlyingBird extends Bird {
    public void fly() {
        // 날기
    }
}

모든 FlyingBirdBird로 대체 가능해야 한다.

💁‍♂️ISP - 인터페이스 분리 원칙

하나의 일반적인 인터페이스보다 여러 개의 구체적인 인터페이스가 낫다.
ISP는 각 역할에 맞게 인터페이스를 분리하는 것이다.
인터페이스 내에 메소드는 최소한의 기능만 제공하면서 하나의 역할에 집중하라는 뜻이다.

위의 SRP 예제에서 남자 클래스를 단일 책임을 갖는 클래스들로 나누었다.
ISP를 적용하면 다양한 역할을 인터페이스로 만들고, 남자 클래스는 그 인터페이스를 구현한 클래스로 만들 수 있다.

SRP와 ISP는 같은 문제에 대한 두 가지 다른 해결책이라고 볼 수 있다.
하지만, 특별한 경우가 아니라면 ISP를 적용하는 것이 더 좋은 해결책이라고 한다.

  • 상위 클래스는 풍성할수록 좋다.
    • 풍성할수록 하위 클래스에게 많은 기능을 확장시켜주는 것이고, 형변환, 코드 중복을 줄여준다.

👩‍👩‍👧‍👦DIP - 의존 역전 원칙

구체적인 것이 추상화된 것에 의존해야 한다. 자주 변경되는 구체 클래스에 의존하지 마라.
의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.
즉, 구체적인 클래스보다 상위 클래스, 인터페이스, 추상 클래스와 같이 변하지 않을 가능성이 높은 클래스와 관계를 맺으라는 것이다.

위와 같이 의존하고 있던 것을 다음과 같이 바꿔라

관계를 타이어 인터페이스로 역전 시킨다. 이것이 의존성 주입(DI)이다.
스프링에서 service와 serviceImpl관계에서 또 나오게 된다.

public interface MessageService {
    void sendMessage(String message);
}
@Service
public class EmailService implements MessageService {
    public void sendMessage(String message) {
        // 이메일 전송 로직
    }
}
@Service
public class SMSService implements MessageService {
	public void sendMessage(String message){
    	// SNS 전송 로직
    }
}

😁결론

저번 시간부터 OOP의 4대 요소인 캡슐화, 상속, 추상화, 다형성 부터 SOLID 법칙 까지 배워봤다. 결국 설계를 잘해야 프로그램 유지 보수 측면에서 굉장히 용이하고 개발 시간과 비용을 절감할 수 있다.

🤗출처

https://dev-coco.tistory.com/142
https://velog.io/@falling_star3/Java-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID
https://devlog-wjdrbs96.tistory.com/380
https://limkydev.tistory.com/77

profile
야호

0개의 댓글