3. 장단점
3.1. 장점
- 상태가 한곳에 몰려있는 코드에비해 상태별로 코드를 파악 할 수있어 유지보수에 용이하다.
- 단위 테스트를 손쉽게 할수있다.
- 기존 코드를 수정하지 않고 상태에 따른 동작을 추가할 수 있다.
3.2. 단점
- 코드 구조가 복잡해진다.
- 상태 구조가 복잡하지 않은 상태에서 패턴을 적용한다면 복잡도 상승만 초래할 수 있다. (주관적으로 판단해야함.)
public class Student {
private final String name;
public Student(String name) {
this.name = name;
}
public void addPrivateCourse(OnlineCourse onlineCourse) {
}
}
public class OnlineCourse {
public enum State {
DRAFT, PUBLISHED, PRIVATE
}
private State state = State.DRAFT;
private List<String> reviews = new ArrayList<>();
private List<Student> students = new ArrayList<>();
public void addReview(String review, Student student) {
// 전체 공개가 되어있을때 아무나 리뷰 작성이 가능함.
if (this.state == State.PUBLISHED) {
this.reviews.add(review);
// 비 공개일 경우 강의에 속한 학생만 리뷰 작성이 가능함.
} else if (this.state == State.PRIVATE && this.students.contains(student)) {
this.reviews.add(review);
} else {
throw new UnsupportedOperationException("리뷰를 작성할 수 없습니다.");
}
}
public void addStudent(Student student) {
// 강의가 만들어지거나 공개된 상태일때는 모든 학생이 수강 가능함.
if (this.state == State.DRAFT || this.state == State.PUBLISHED) {
this.students.add(student);
// 비공개 상태일 경우 특정 조건을 만족하는 학생만 수강 가능함.
} else if (this.state == State.PRIVATE && availableTo(student)) {
this.students.add(student);
} else {
throw new UnsupportedOperationException("학생을 해당 수업에 추가할 수 없습니다.");
}
}
public void changeState(State newState) {
this.state = newState;
}
/**
* 소스를 인위적으로 복잡하게 하기위해 만들어짐
*/
private boolean availableTo(Student student) {
return true;
}
public State getState() { return state; }
public List<String> getReviews() { return reviews; }
public List<Student> getStudents() { return students; }
}
public class StatePatternClient {
public static void main(String[] args) {
Student student = new Student("jin.bak");
OnlineCourse onlineCourse = new OnlineCourse();
student.addPrivateCourse(onlineCourse);
onlineCourse.addStudent(student);
onlineCourse.changeState(State.PRIVATE);
onlineCourse.addStudent(student);
onlineCourse.addReview("Hello", student);
System.out.println(onlineCourse.getState());
System.out.println(onlineCourse.getStudents());
System.out.println(onlineCourse.getReviews());
}
}
public interface State {
void addReview(String review, Student student);
void addStudent(Student student);
}
public class Draft implements State {
private final OnlineCourse onlineCourse;
public Draft(OnlineCourse onlineCourse) {
this.onlineCourse = onlineCourse;
}
@Override
public void addReview(String review, Student student) {
throw new UnsupportedOperationException("드래프트 상태에서는 리뷰를 남길 수 없습니다.");
}
@Override
public void addStudent(Student student) {
this.onlineCourse.getStudents().add(student);
if (this.onlineCourse.getStudents().size() > 1) {
this.onlineCourse.changeState(new Private(this.onlineCourse));
}
}
}
public class Published implements State {
private final OnlineCourse onlineCourse;
public Published(OnlineCourse onlineCourse) {
this.onlineCourse = onlineCourse;
}
@Override
public void addReview(String review, Student student) {
this.onlineCourse.getReviews().add(review);
}
@Override
public void addStudent(Student student) {
this.onlineCourse.getStudents().add(student);
}
}
public class Private implements State {
private final OnlineCourse onlineCourse;
public Private(OnlineCourse onlineCourse) {
this.onlineCourse = onlineCourse;
}
@Override
public void addReview(String review, Student student) {
if (this.onlineCourse.getStudents().contains(student)) {
this.onlineCourse.getReviews().add(review);
} else {
throw new UnsupportedOperationException("프라이빗 코스는 학생만 리뷰를 남길수 있습니다.");
}
}
@Override
public void addStudent(Student student) {
if (student.isAvailable(this.onlineCourse)) {
this.onlineCourse.getStudents().add(student);
} else {
throw new UnsupportedOperationException("프라이빗 코스를 수강할 수 없습니다.");
}
}
}
public class OnlineCourse {
private State state = new Draft(this);
private List<Student> students = new ArrayList<>();
private List<String> reviews = new ArrayList<>();
public void addStudent(Student student) {
this.state.addStudent(student);
}
public void addReview(String review, Student student) {
this.state.addReview(review, student);
}
public State getState() { return state; }
public List<Student> getStudents() { return students; }
public List<String> getReviews() { return reviews; }
public void changeState(State state) {
this.state = state;
}
}
public class AfterStateClient {
public static void main(String[] args) {
Student student = new Student("jin-park");
Student otherStudent = new Student("other user");
OnlineCourse onlineCourse = new OnlineCourse();
otherStudent.addPrivate(onlineCourse);
onlineCourse.addStudent(student);
onlineCourse.changeState(new Private(onlineCourse));
onlineCourse.addReview("Hello", student);
onlineCourse.addStudent(otherStudent);
System.out.println(onlineCourse);
}
}
위글은 인프런의 코딩으로 학습하는 GoF의 디자인 패턴강의를 정리하였습니다.
백기선님의 수락으로 정리하였으며 더 자세한 내용은 강의를 수강하시기 바랍니다.
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard
22. 템플릿 메소드 패턴 (0) | 2022.02.11 |
---|---|
21. 전략 패턴 (0) | 2022.02.11 |
19. 옵저버 패턴 (0) | 2022.02.11 |
18. 메멘토 패턴 (0) | 2022.02.10 |
17. 중재자 패턴 (0) | 2022.02.10 |