객체지향 5대 원칙이라고 불리는 SOLID Principles은 Single Responsiblity Principle, Open-Closed Principle, Liskov Substitution Principle, Dependency Inversion Principle, Interface Segregation Principle으로 이루어져있다. 유지 보수와 확장이 쉬운 프로그램을 설계하기 위해 앞선 원칙들을 적용한다. 즉, 이 다섯가지 원칙을 적용한다면 객체지향 프로그래밍을 하게 되는 것이다.
Single Responsiblity Principle (단일 책임 원칙)
책임이란 단어가 다소 추상적으로 느껴질 수 있지만 '기능'이라고 보면 된다. 함수, 클래스 등은 단 하나의 책임을 가져야 한다는 원칙이다. 이를 지키면 새로운 요구사항이 생기거나 변경이 필요할 때 영향을 받는 부분이 적어진다는 효과가 있다. 클래스내에 A, B, C 메소드가 있을 때 A 메소드의 결과를 B 메소드가 이용하고, B 메소드의 결과를 C가 이용한다고 하자. A 메소드가 수정되면 B, C 메소드도 영향을 받게 된다. 연쇄적인 영향을 막기 위해서 책임을 분리하여 작성할 필요가 있다.
구민센터에서 스포츠강좌를 수강하려고 한다. 찜 목록에 담아둔 강좌를 다른 강좌로 변경하고 싶을 때는 두 가지 방법이 존재한다. 기존 강좌의 이름을 바꾸는 것과 기존 강좌를 삭제하고 다시 담는 것이다.
public class Course {
private String name;
public Course(final String name) {
this.name = name;
}
public String getName() {
return name;
}
void setName(final String name) {
this.name = name;
}
}
public class Resident {
private List<Course> courses;
public Resident() {
courses = new ArrayList<>();
}
public void insertCourse(final Course course) {
courses.add(course);
}
// 주민이 강좌 객체를 변화시키는 영향을 줌 => SRP 위반
public void replaceCourse(final Course course, final String courseName) {
courses.stream()
.filter(Course -> Course.equals(course))
.forEach(Course -> Course.setName(courseName));
}
// SRP 준수
public void updateCourse(final Course course, final Course updatedCourse) {
courses.remove(course);
courses.add(updatedCourse);
}
public List<Course> getCourses() {
return Collections.unmodifiableList(courses);
}
}
실제로 테스트를 해보면 replaceCourse 메서드를 통해 강좌를 변경할시 강좌 객체에 변화를 준다.
Open-Closed Principle (개방-폐쇄 원칙)
확장에는 열려있고, 변경에는 닫혀있어야 한다는 원칙이다. 이 원칙을 볼 때마다 흥선대원군이 생각난다.. 추상화, 다형성(상속)을 통해 구현할 수 있다.
public class Welcome {
private Honggildong honggildong;
public static void main(String[] args) {
Welcome welcome = new Welcome();
welcome.hello();
}
private void hello() {
System.out.println("Welcome!");
honggildong = new Honggildong();
honggildong.hello();
}
}
public class Honggildong {
public void hello() {
System.out.println("홍길동님 안녕하세요, 환영합니다.");
}
}
사원명에 따라 환영 인사를 하는 프로그램이 있다. 만약 프로그램의 사용자가 이순신으로 바뀐다면 Leesoonshin이라는 클래스를 생성하여 hello 메서드를 수행해야 한다. 단순히 사원명만 변경하는 것인데 수정을 위해 서버를 중단해야 한다던가 하는 일이 일어날 수도 있다. 이러한 문제를 해결하기 위해서는 추상화가 필요하다.
public class Welcome {
private Name name;
public static void main(String[] args) {
Welcome welcome = new Welcome();
welcome.setName(new Leesoonshin());
welcome.hello();
}
private void setName(Name name) {
this.name = name;
}
private void hello() {
System.out.println("Welcome!");
messenger.hello();
}
}
public class Leesoonshin implements Name {
@Override
public void hello() {
System.out.println("이순신님 안녕하세요, 환영합니다.");
}
}
public interface Name {
void hello();
}
interface를 구현(implements)하는 방식으로 변경하면 어떤 사원으로 대체가 되어도 유연하게 대응할 수 있다. 개념이 비슷하여 extends와 헷갈릴 수도 있다. extends는 일반 클래스, abstract 클래스 상속에 이용되고 implements는 interface 상속에 이용된다. 또 extends는 하나의 클래스만 상속 받을 수 있고 implements는 여러개의 다중 상속이 가능하다. 즉, extends는 클래스를 확장 하는 것이고 implements는 interface를 구현하는 것이다.
* 아래의 자료들을 참고하였습니다.
'Programming' 카테고리의 다른 글
디자인패턴 시리즈 4. 팩토리 패턴 (Factory Pattern) (0) | 2023.01.16 |
---|---|
디자인패턴 시리즈 3. 데코레이터 패턴 (Decorator Pattern) (0) | 2023.01.13 |
디자인패턴 시리즈 2. 싱글톤 패턴 (Singleton Pattern) (0) | 2023.01.12 |
디자인패턴 시리즈 1. 전략 패턴 (Strategy Pattern) (2) | 2023.01.11 |
커밋 내역 관리를 위한 git merge, rebase, squash (0) | 2022.12.22 |
댓글