728x90
✏️ 개요
- SOLID 원칙이란 객체지향 설계에서 지켜줘야 할 5개의 소프트웨어 개발 원칙을 말한다.
- 해당 용어의 개념 이론들은 oop의 4가지 특징(추상화, 상속, 다형성, 캡슐화) 등의 개념들을 재정립한 것이다.
- 또한 5가지 원칙들은 서로 개념적으로 연관되어 있다.
- SRP : 단일 책임 원칙 (single responsibility principle)
- OCP : 개방-폐쇄 원칙 (Open/closed principle)
- LSP : 리스코프 치환 원칙 (Liskov substitution principle)
- ISP : 인터페이스 분리 원칙 (Interface segregation principle)
- DIP : 의존관계 역전 원칙 (Dependency inversion priciple)
❓ 좋은 설계란 무엇인가
- 좋은 설계란 시스템에 새로운 요구사항이나 변경사항이 있을 때, 영향을 받는 범위가 적은 구조를 말한다.
- SOLID 객체 지향 원칙을 적용하면 코드를 확장하고 유지보수 관리가 더 쉬워지며, 복잡한 복잡성을 제거해 리팩토링에 소요되는 시간을 줄임으로써 프로젝트 개발의 생산성을 높일 수 있다.
1. SRP
- 단일 책임 원칙으로 클래스(객체)는 단 하나의 책임만 가져야한다는 원칙이다.
- 즉, 하나의 클래스는 하나의 기능 담당하라는 의미이다.
- 따라서 SRP 원칙을 따름으로써 한 책임의 변경으로부터 다른 책임의 변경으로의 연쇄작용을 극복할 수 있게된다.
- 정리하면, SRP는 프로그램의 유지보수 성을 높이기 위한 설계 기법이다.
2. OCP
- 클래스는 확장에는 열려있어야 하며, 수정에는 닫혀있어야 한다를 뜻한다.
- 확장에 열려있다 : 새로운 변경 사항이 발생했을 때, 유연하게 코드를 추가함으로써 큰 힘을 들이지 않고, 애플리케이션의 기능을 확장할 수 있다.
- 변경에 닫혀있다 : 새로운 변경 사항이 발생했을 때, 객체의 직접 수정을 제한한다.
- 결론부터 말하면, OCP 원칙은 추상화 사용을 통한 관계 구축을 권장한다는 의미이다.
- 즉, 다형성과 확장을 가능하게 하는 객체지향의 장점을 극대화하는 기본적인 설계 원칙이다.
- 추상화를 잘못 설계하면 LSP와 ISP 위반으로 이어지게 된다.
- OCP는 DIP의 설계 기반이 되기도 한다.
❓ 어떤식으로 OCP 대로 추상화 설계를 할 것인가
- 먼저 변경(확장)될 것과 변하지 않을 것을 엄격히 구분한다.
- 이 두 모듈이 만나는 지점에 추상화(추상클래스 or 인터페이스)를 정의한다.
- 정의한 추상화에 의존하도록 코드를 작성한다.
// 추상화
abstract class Animal {
abstract void speak();
}
class Cat extends Animal { // 상속
void speak() {
System.out.println("냐옹");
}
}
class Dog extends Animal { // 상속
void speak() {
System.out.println("멍멍");
}
}
// 추상클래스를 상속만 하면 메소드 강제 구현 규칙으로 규격화만 하면 확장에 제한 없다 (opened)
class Sheep extends Animal {
void speak() {
System.out.println("매에에");
}
}
class Lion extends Animal {
void speak() {
System.out.println("어흥");
}
}
// 기능 확장으로 인한 클래스가 추가되어도, 더이상 수정할 필요가 없어진다 (closed)
class HelloAnimal {
void hello(Animal animal) {
animal.speak();
}
}
public class Main {
public static void main(String[] args) {
HelloAnimal hello = new HelloAnimal();
Animal cat = new Cat();
Animal dog = new Dog();
Animal sheep = new Sheep();
Animal lion = new Lion();
hello.hello(cat); // 냐옹
hello.hello(dog); // 멍멍
hello.hello(sheep); // 매에에
hello.hello(lion); // 어흥
}
}
3. LSP
- 다형성을 지원하기 위한 원칙이다.
- LSP 원칙은 서브 타입은 언제나 부모 타입으로 교체할 수 있어야 한다는 원칙이다.
- 즉, 부모 클래스의 인스턴스를 사용하는 위치에서 자식 클래스의 인스턴스를 대신 사용했을 때, 코드가 원래 의도대로 작동해야 한다는 의미이다.
- 이것을 부모 클래스와 자식 클래스 사이의 행위가 일관성이 있다고 말한다.
📌 LSP 원칙 위반
- 핵심은 부모 클래스의 행동 규약을 자식 클래스가 위반하면 안된다는 것이다.
- 자식의 잘못된 메서드 Overloading
class Animal {
int speed = 100;
int go(int distance) {
return speed * distance;
}
}
class Eagle extends Animal {
String go(int distance, boolean flying) {
if (flying)
return distance + "만큼 날아서 갔습니다.";
else
return distance + "만큼 걸어서 갔습니다.";
}
}
public class Main {
public static void main(String[] args) {
Animal eagle = new Eagle();
eagle.go(10, true);
}
}
- 부모의 의도와 다르게 메서드 Overloading
🎯 결론
- LSP의 핵심은 사전에 약속한 기획대로 구현하고, 상속시 부모에서 구현한 원칙을 따라가야 한다가 이 원칙의 핵심이다.
- 협업하는 개발자 사이의 신뢰를 위한 원칙이다.
- 코드를 수정해야한다면, 인터페이스로 빼서 따로 작업을 통해 수정을 해야한다.
abstract class Animal {
}
interface Speakable {
void speak();
}
class Cat extends Animal implements Speakable {
public void speak() {
System.out.println("냐옹");
}
}
class dog extends Animal implements Speakable {
public void speak() {
System.out.println("멍멍");
}
}
class Fish extends Animal {
}
4. ISP
- 인터페이스의 단일 책임 원칙을 강조
5. DIP
- 어떤 클래스를 참조해서 사용해야 하는 상황이 생긴다면 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻이다.
728x90
'디자인 패턴 > OOP' 카테고리의 다른 글
OOP (0) | 2023.09.07 |
---|---|
OOP의 4가지 특징 (0) | 2023.06.09 |
인터페이스와 다형성(polymorphism) 그리고 추상클래스 (0) | 2023.06.07 |