이 포스팅을 어케 적게 되었냐 하면.. 앞선 불공변 얘기를 하며 리스코프 치환 원칙
에 대한 언급이 나와서이다.. 5원칙을 얘기만 들어봤지 객체지향을 공부하며 더 찾아볼 생각을 하지 않아서,,
아래 다섯가지의 이름에서 앞 글자를 따 SOLID
라고 불리기도 한다. 객체지향 원칙은 클린코드의 저자인 로버트 마틴에 의해 2009년에 명명되었다.
가볍게 객체지향 프로그래밍
에 대해 정의해보자면 (내 주변의 아주 멋있는 개발자 say) 모의 실험을 통해 탄생한 '객체지향' 이라는 개념을 클래스를 통해 인스턴스를 만듦으로써 실현되는 프로그래밍 방식이다.
객체지향 그냥 내 기준에 맞춰서 프로그래밍 하면 되지 않나..? 싶을 수 있지만 실생활에서 생각해보자. 우리도 대한민국 법 아래에서 법(원칙)을 준수하며 살아가지 않은가? 그럼 왜 지키는가? 법을 지킴으로써 모두의 삶의 질을 높일 수 있지 않은가? (범죄 방지 등등..)
이제 소개할 객체지향의 5가지 원칙도 그러하다. 이 원칙을 지키면, 객체지향 프로그래밍을 더욱 효과적으로 수행할 수 있기 때문이다 (확장성 Good, 유지보수 Good 등등).
= 단일 책임 원칙
변경
이다.이해하기 쉽게 이 원칙에 대해 예시를 들자면, (인건비를 아끼기 위해) 학원에 수학과 영어를 모두 가르치는 선생님 한명만 뒀다고 생각해보자. 인건비를 아껴서 좋겠지만, 만약 선생님이 아프거나 일을 그만둔다면 당장 이 모든 수업을 감당할 선생님이 없어 학원은 수학 선생님, 영어 선생님을 모두 구해야 하므로 타격이 클 것이다.
class Car {
private String brand;
//자동차와 관련된 책임만을 가짐
public void startEngine() {} //엔진 키는 로직
public void accelerate() {} //가속하는 로직
}
= 개방 폐쇄 원칙
추상화(인터페이스)
, 다형성(상속)
interface Shape {
//메서드 내용이 변할 여지가 많으므로 추상화시킴
double calculateArea();
}
class Circle implements Shape {
private double radius;
public double calculateArea() {
return Math.PI * radius * radius;
}
}
= 리스코프 치환 원칙
상속
, 제네릭 한정적 와일드 카드(는 내가 넣음ㅋ)class Vehicle {
// ...
public void startEngine() {
// 엔진을 시작하는 로직
}
}
//Car 클래스는 Vehicle 타입으로 대체 가능
class Car extends Vehicle {
// ...
public void accelerate() {}
}
= 인터페이스 분리 원칙 (= 인터페이스의 단일 책임)
이도 이해하기 쉽게 예시를 들어본다. 동물이라는 인터페이스가 있다면, 강아지, 고양이 등의 클래스가 존재할 것이다. 우리는 강아지, 고양이 클래스를 사용하지 위해 동물 인터페이스를 구현하였다. 이때, 강아지 클래스를 수정하게 되면, 이것과 관련이 없는 고양이 클래스도 영향을 받게 된다.
//각각 프린트, 스캔 기능을 갖는 인터페이스 따로 구현
interface Printer {
void print();
}
interface Scanner {
void scan();
}
class FaxMachine implements Printer {
public void print() {
}
}
= 의존 역전 원칙
※ 의존성 주입 = 외부에서 두 객체 간의 관계를 결정하고 주입하는 것
interface DataAccessObject {
void saveData(String data);
}
class DatabaseDAO implements DataAccessObject {
public void saveData(String data) {
}
}
class FileDAO implements DataAccessObject {
public void saveData(String data) {
}
}
class DataManager {
// 이 클래스는 DAO 인터페이스에 의존
// 실제 구현할 클래스는 런타임에 결정
private DataAccessObject dao;
public DataManager(DataAccessObject dao) {
this.dao = dao;
}
public void processData(String data) {
dao.saveData(data);
}
}
https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EC%95%84%EC%A3%BC-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-SRP-%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99
https://sihyung92.oopy.io/oop/solid