일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 티스토리 쿠키 삭제
- 선형대수
- 스프링부트핵심가이드
- 이터레이터
- 자료구조와 함께 배우는 알고리즘 입문
- 스프링 시큐리티
- 구멍가게코딩단
- iterator
- ㅒ
- network configuration
- Kernighan의 C언어 프로그래밍
- 페이징
- 코드로배우는스프링웹프로젝트
- 처음 만나는 AI 수학 with Python
- d
- resttemplate
- 친절한SQL튜닝
- baeldung
- 데비안
- 서버설정
- /etc/network/interfaces
- 코드로배우는스프링부트웹프로젝트
- 알파회계
- 목록처리
- 처음 만나는 AI수학 with Python
- 리눅스
- 네트워크 설정
- GIT
- 자료구조와함께배우는알고리즘입문
- 자바편
- Today
- Total
bright jazz music
Compound Pattern: 6. 지금까지의 내용 리뷰 본문
Compound Pattern: 6. 지금까지의 내용 리뷰
bright jazz music 2022. 11. 5. 13:35https://github.com/hojuncha997/designPatternStudy/tree/main/src/main/java/com/example/designpatternstudy/compoundPattern
1. QuackableInterfaceForCompoundPattern 생성 (오리 생성)
- 처음엔 QuackableInterfaceForCompoundPattern 인터페이스를 만들었다.
- 이 인터페이스는 오리 소리를 낼 수 있는여러 종류의 오리를 만들기 위해 작성되었으며 public void Quack() 메소드를 가지고 있다.
- MallardDuck, RedHeadDuck, DuckCall, RubberDuck 과 같은 오리 클래스들이 이 인터페이스를 구현(implements)하였다.
//QuackableInterfaceForCompoundPattern.java
package com.example.designpatternstudy.compoundPattern;
public interface QuackableInterfaceForCompoundPattern {
public void quack();
}
2. Adapter Pattern (GooseAdapter 생성)
- GooseAdapter는 Goose(거위)를 오리(QuackableInterfaceForCompoundPattern)로 만들기 위해 만든 클래스이다.
- Goose클래스는 오리가 아니므로 QuackableInterfaceForCompoundPattern인터페이스를 구현하지 않는다. 따라서 오리만 사용 가능한 프로그램에서는 사용할 수 없다.
- Goose가 QuackableInterfaceForCompoundPattern를 구현하게 만든다면 오리가 되므로 해당 프로그램을 사용할 수 있겠지만 기존 코드가 수정되므로 Open-Closed Principle을 위반한다. 또한 해당 클래스는 형식적으로는 오리겠지만 실질적으로는 오리도, 거위도 아닌 상태가 되어버린다.
- 따라서 Goose를 오리로 만들 수 있는 GooseAdapter를 생성한다. 이 때 GooseAdapter는 QuackableInterfaceForCompoundPattern 인터페이스를 구현(implements)해야 하며 Goose를 멤버 변수로서 가져야 한다.
- public void quack()을 오버라이드 하면서 그 내부의 기능을 멤버 변수 Goose에게 위임한다.
- QuackableInterfaceForCompoundPattern gooseDuck = new GooseAdapter(new Goose());와 같이 객체를 생성한다.
//어댑터 클래스에서는 타겟 인터페이스를 구현해야 한다.
// 여기서는 QuackableInterfaceForCompoundPattern이 타겟
public class GooseAdapter implements QuackableInterfaceForCompoundPattern {
Goose goose;
//생성자
public GooseAdapter(Goose goose){
this.goose = goose;
}
@Override
public void quack() {
goose.honk();
}
}
3. Decorator Pattern(QuackCountingDecorator 생성)
- 오리가 소리낸 횟수를 세고 싶었기 때문에 데코레이터 패턴을 사용하였다. 데코레이터 패턴은 기존의 코드를 수정하지 않으면서 새로운 기능을 추가할 때 사용하는 패턴이다.
- 우선 QuackCountingDecorator.java를 생성하였다. 이 클래스 역시 QuackableInterfaceForCompoundPattern 인터페이스를 구현한다. GooseAdapter가 Goose 객체를 감싸듯이, QuackCountingDecorator는 오리 객체를 감싸줘야 하기 때문이다.
- QuackableInterfaceForCompoundPattern mallardDuck = new QuackCountingDecorator(new MallardDuck());와 같이 객체를 생성한다.
//QuackCountingDecorator.java
package com.example.designpatternstudy.compoundPattern;
//데코레이터. 어댑터와 마찬가지로 타겟 인터페이스 구현 필요
public class QuackCountingDecorator implements QuackableInterfaceForCompoundPattern {
//감싸고자 하는 객체의 레퍼런스를 저장하는 인스턴스 변수 필요
QuackableInterfaceForCompoundPattern duck;
static int numberOfQuacks;
//생성자: 생성자에서 감싸고 있는 타겟 인터페이스의 레퍼런스를 가져온다.
public QuackCountingDecorator(QuackableInterfaceForCompoundPattern duck){
this.duck = duck;
}
@Override
public void quack() {//호출 시 내부의 객체에게 동작을 위임.
duck.quack();
numberOfQuacks++;
}
public static int getQuacks(){
return numberOfQuacks;
}
}
4. Factory Pattern (AbstractDuckFactory, CountingDuckFactory, DuckFactory 생성)
- 데코레이터를 사용해서 각각의 오리 객체를 감싸주는 일은 번거로울 뿐만 아니라 위험한 작업이다. 프로그램이 복잡해지면 해당 작업을 누락할 수도 있기 때문이다.
- 따라서 추상 팩토리 패턴을 사용하여 팩토리가 객체를 만들도록 하였다.
- 오리 객체를 만들 때는 항상 팩토리에 요청하므로 팩토리가 데코레이터에 싸여 있는 오리를 리턴하게 하였다.(애초에 소리 카운팅 기능이 있는 오리가 생산돼 나오는 것이므로 누락 염려가 없다.)
- QuackCountingDecorator로 장식되지 않은(감싸지지 않은) 오리를 원한다면 다른 팩토리를 쓰면 된다. 실습에서는 DuckFactory 클래스를 사용하면 데코레이터로 장식되지 않은 오리가 반환된다.
//AbstractDuckFactory.java
//새로운 기능을 사용할 때는 객체를 데코레이터로 감싸야만 가능
//이 감싸는 작업을 따로 빼내어 한 군데서 하기 위해 팩토리 사용
package com.example.designpatternstudy.compoundPattern;
//추상 클래스
public abstract class AbstractDuckFactory {
//추상 메서드
public abstract QuackableInterfaceForCompoundPattern createMallardDuck();
public abstract QuackableInterfaceForCompoundPattern createRedheadDuck();
public abstract QuackableInterfaceForCompoundPattern createDuckCall();
public abstract QuackableInterfaceForCompoundPattern createRubberDuck();
}
//CountingDuckFactory.java : QuackCountingDecorator로 감싸진 오리 객체 반환
package com.example.designpatternstudy.compoundPattern;
public class CountingDuckFactory extends AbstractDuckFactory{
//모든 메서드에서 QuackableInterfaceForCompoundPattern객체를
//QuackCountingDecorator데코레이터로 감싼다.
//시뮬레이터는 데코레이터로 감싼 객체가 반환된다는 것을 알 수 없다.
//이전과 똑같이 QuackableInterfaceForCompoundPattern를 반환받았다고 여긴다.
@Override
public QuackableInterfaceForCompoundPattern createMallardDuck() {
return new QuackCountingDecorator(new MallardDuck());
}
@Override
public QuackableInterfaceForCompoundPattern createRedheadDuck() {
return new QuackCountingDecorator(new RedheadDuck());
}
@Override
public QuackableInterfaceForCompoundPattern createDuckCall() {
return new QuackCountingDecorator(new DuckCall());
}
@Override
public QuackableInterfaceForCompoundPattern createRubberDuck() {
return new QuackCountingDecorator(new RubberDuck());
}
}
//DuckFactory.java
//데코레이터가 없는 오리 생성 팩토리
package com.example.designpatternstudy.compoundPattern;
public class DuckFactory extends AbstractDuckFactory{ //추상 팩토리 확장
//각 메소드는 QuackableInterfaceForCompoundPattern 인터페이스 객체를 만든다.
//시뮬레이터는 실제 어떤 제품이 만들어지는지 알 수 없다.
//단순히 QuackableInterfaceForCompoundPattern이 리턴된다는 것만 안다.
@Override
public QuackableInterfaceForCompoundPattern createMallardDuck() {
return new MallardDuck();
}
@Override
public QuackableInterfaceForCompoundPattern createRedheadDuck() {
return new RedheadDuck();
}
@Override
public QuackableInterfaceForCompoundPattern createDuckCall() {
return new DuckCall();
}
@Override
public QuackableInterfaceForCompoundPattern createRubberDuck() {
return new RubberDuck();
}
}
용례
AbstractDuckFactory duckFactory = new CountingDuckFactory();
QuackableInterfaceForCompoundPattern mallardDuck =
duckFactory.createMallardDuck(); // 데코레이터로 감싸진 MallardDuck 반환
5. Composite Pattern + iterator패턴 (Flock)
모든 오리와 거위, QuackableInterfaceForCompound 객체를 관리하기 어려워졌다. 따라서 Composite 패턴을 사용하여 오리들을 모아서 무리 단위로 관리하기로 하였다. 이 패턴을 사용하면 오리를 종별로 나눠서 관리할 수도 있다.
//Flock.java
//오리 무리를 만드는 클래스
//composite패턴 사용: 객체들로 구성된 컬렉션을 개별 객체와 같은 방식으로 다룰 수 있게 해준다.
package com.example.designpatternstudy.compoundPattern;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//복합객체와 잎 원소에서 같은 인터페이스를 구현해야 한다.
//여기서는 QuackableInterfaceForCompoundPattern이 잎 원소가 된다.
public class Flock implements QuackableInterfaceForCompoundPattern {
List<QuackableInterfaceForCompoundPattern> quackers
= new ArrayList<QuackableInterfaceForCompoundPattern>();
//Flock에 QuackableInterfaceForCompoundPattern(오리)을 추가하는 메서드
public void add(QuackableInterfaceForCompoundPattern quacker){
//List에 새로운 QuackableInterfaceForCompoundPattern(오리)추가
quackers.add(quacker);
}
@Override
public void quack() {
//반복자(Iterator)패턴 사용
//오리 리스트(quackers)를 이터레이터로 만든다.
Iterator<QuackableInterfaceForCompoundPattern> iterator
= quackers.iterator();
while (iterator.hasNext()) {
//이터레이터에 남은 원소가 없을 때까지 반복한다.
QuackableInterfaceForCompoundPattern quacker = iterator.next();
quacker.quack();
}
}
}
//DuckSimulator.java
package com.example.designpatternstudy.compoundPattern;
public class DuckSimulator {
public static void initDuckSimul(){
DuckSimulator simulator = new DuckSimulator();
//simulate()메서드에 전달할 팩토리 생성(데코레이터 사용)
AbstractDuckFactory duckFactory = new CountingDuckFactory();
//파라미터 추가
simulator.simulateAll(duckFactory);
}
//파라미터 추가
void simulateAll(AbstractDuckFactory duckFactory){
QuackableInterfaceForCompoundPattern redheadDuck = duckFactory.createRedheadDuck();
QuackableInterfaceForCompoundPattern duckCall = duckFactory.createDuckCall();
QuackableInterfaceForCompoundPattern rubberDuck = duckFactory.createRubberDuck();
QuackableInterfaceForCompoundPattern gooseDuck = new GooseAdapter(new Goose());
System.out.println("\n오리 시뮬레이션 게임: 무리 (+ 컴포지트)");
Flock flockOfDucks = new Flock();
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
flockOfDucks.add(gooseDuck);
//물오리만 들어가는 Flock객체(Composite객체) 생성
Flock flockOfMallards = new Flock();
//개별 물오리(mallard) 생성
QuackableInterfaceForCompoundPattern mallardOne = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardTwo = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardThree = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardFour = duckFactory.createMallardDuck();
//개별 물오리를 컴포지트 객체에 추가하기
flockOfMallards.add(mallardOne);
flockOfMallards.add(mallardTwo);
flockOfMallards.add(mallardThree);
flockOfMallards.add(mallardFour);
//물오리 무리(flockOfMallards)를 아까 만든 오리 무리(flockOfDucks)에 넣는다.
flockOfDucks.add(flockOfMallards);
System.out.println("\n오리 시뮬레이션 게임: 전체 무리");
simulate(flockOfDucks);
System.out.println("\n오리 시뮬레이션 게임: 물오리 무리");
simulate(flockOfMallards);
System.out.println("오리가 소리 낸 횟수:" +
QuackCountingDecorator.getQuacks() + " 번");
}
//데코레이터도 QuackableInterfaceForCompoundPatter 인터페이스이다.
void simulate(QuackableInterfaceForCompoundPattern duck){
duck.quack();
}
}
//
//오리 시뮬레이션 게임: 무리 (+ 컴포지트)
//
//오리 시뮬레이션 게임: 전체 무리
//꽥꽥
//꽉꽉
//삑삑
//끽끽
//꽥꽥
//꽥꽥
//꽥꽥
//꽥꽥
//
//오리 시뮬레이션 게임: 물오리 무리
//꽥꽥
//꽥꽥
//꽥꽥
//꽥꽥
//오리가 소리 낸 횟수:11 번
6. Observer Pattern (QuackObservable, Observable, Observer 생성) + QuackableInterfaceForCompoundPattern와 그 구현 클래스 전부 수정
- 오리들(QuackableInterfaceForCompound)이 소리 냈을 때 바로 연락받고 싶어졌다. 따라서 옵저버 패턴을 사용하였다.
- QuackObservable 인터페이스를 생성한다. 이 인터페이스는 옵저버를 등록하는 메소드인 registerObserver(Observer observer) 메소드와, 옵저버에게 연락을 돌리는 notifyObservers() 메소드를 가지고 있다.
- 오리들(QuackableInterfaceForCompoundPattern)을 감시하고자 오리들로 하여금 QuackObservable을 확장하게 하였다.
- QuackableInterfaceForCompoundPattern 인터페이스를 구현하는 클래스들이 QuackObservable의 메소드를 구현하도록 일일이 작업해야 했지만 다른 방식을 사용했다.
- 옵저버 등록 및 연락을 돌리는 코드를 캡슐화하여 갖는 Observable 클래스를 보조 클래스로 생성하는 것이다. Observable클래스는 QuackObservable 인터페이스를 구현함으로써 Quackable 인터페이스의 등록, 연락 메소드를 보유할 수 있다. 이렇게 하면 실제 코드는 Observable에 한 번만 써놓고 QuackObservable이 필요한 작업을 Observable에 전부 위임할 수 있다.
- QuackableInterfaceForCompoundPattern인터페이스의 구현 클래스들로 하여금 Observable observable을 레퍼런스로 추가한다. 그리고 registerObserver()의 내부에서 observable에게 메소드 실행을 위임한다.
- Observer 인터페이스를 생성한다. 이 인터페이스는 public void update(QuackObservable duck) 메소드를 보유한다.
- Quackologist 클래스를 생성한다. 이 클래스가 Observer 인터페이스를 구현하여 옵저버의 역할을 하게 된다.
QuackObservable 인터페이스 생성
//QuackObservable.java
package com.example.designpatternstudy.compoundPattern;
//개별 객체의 동작을 감시하고자 할 때 사용
//여기서는 QuackableInterfaceForCompoundPattern을 의미한다.
public interface QuackObservable {
//옵저버를 등록하는 메소드
//Observer 인터페이스를 구현하는 객체라면 어떤 객체든 꽥꽥 소리 내는 걸 감시할 수 있다.
//여기서는 QuackableInterfaceForCompoundPattern에서 구현한다.
public void registerObserver(Observer observer);
//옵저버에 연락을 돌리는 메소드
public void notifyObservers();
}
QuackableInterfaceForCompoundPattern 수정
( QuackObservable인터페이스 확장)
//QuackableInterfaceForCompoundPattern.java
package com.example.designpatternstudy.compoundPattern;
//개별 객체(오리)를 감시하고 싶어서 이 인터페이스로하여금 Observable 클래스를 확장하도록 하였다.
public interface QuackableInterfaceForCompoundPattern extends QuackObservable {
public void quack();
}
Observable 클래스 생성
(QuackObservable의 보조 클래스로서 QuackObservable클래스를 구현하여 등록과 연락 기능을 캡슐화 하여 보유한다. 따라서 QuackableInterfaceForCompoundPattern 인터페이스의 구현클래스들이 각각 메소드를 구현하지 않고도 Observable에게 구현을 위임할 수 있음. 물론 QuackableInterfaceForCompoundPattern 의 구현클래스들은 Observable을 참조로서 클래스에 추가해야 함.)
//Observable.java
package com.example.designpatternstudy.compoundPattern;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Observable implements QuackObservable{
List<Observer> observers = new ArrayList<Observer>();
QuackObservable duck;
public Observable(QuackObservable duck){
this.duck = duck;
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void notifyObservers() {
// Iterator iterator = observers.iterator();
// 위 코드대로 하면 경고 발생 : Raw use of parameterized class 'Iterator'
Iterator<Observer> iterator = observers.iterator();
while (iterator.hasNext()){
Observer observer = iterator.next();
observer.update(duck);
}
}
}
QuackableInterfaceForCompoundPattern의 구현클래스들과 Observable의 결합.
(Observable을 레퍼런스로서 추가하고, 등록과 연락 메소드에서 observable에게 구현을 위임한다. 따라서 개별적으로 구현부를 작성해 줄 필요가 없다. 예시는 MallardDuck만 들었으며 다른 오리들도 똑같이 하면 된다.)
//MallardDuck.java
package com.example.designpatternstudy.compoundPattern;
//청둥오리
public class MallardDuck implements QuackableInterfaceForCompoundPattern {
Observable observable;
public MallardDuck(){
observable = new Observable(this);
}
@Override
public void quack() {
System.out.println("꽥꽥");
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observable.registerObserver(observer);
}
@Override
public void notifyObservers() {
observable.notifyObservers();
}
}
Observer 인터페이스 생성
(실질적으로 옵저버 역할을 할 Quackologist 클래스가 이 인터페이스를 구현한다.)
//Observer.java
package com.example.designpatternstudy.compoundPattern;
public interface Observer {
public void update(QuackObservable duck);
}
Quackologist 클래스 생성
(실질적으로 옵저버 역할을 하는 클래스)
//Quackologist.java
package com.example.designpatternstudy.compoundPattern;
public class Quackologist implements Observer {
@Override
public void update(QuackObservable duck) {
System.out.println("꽥꽥학자: " + duck + " 가 방금 소리냈다.");
}
}
DuckSimulator 수정
//DuckSimulator.java
package com.example.designpatternstudy.compoundPattern;
public class DuckSimulator {
public static void initDuckSimul(){
DuckSimulator simulator = new DuckSimulator();
//simulate()메서드에 전달할 팩토리 생성(데코레이터 사용)
AbstractDuckFactory duckFactory = new CountingDuckFactory();
//파라미터 추가
simulator.simulateAll(duckFactory);
}
//파라미터 추가
void simulateAll(AbstractDuckFactory duckFactory){
QuackableInterfaceForCompoundPattern redheadDuck = duckFactory.createRedheadDuck();
QuackableInterfaceForCompoundPattern duckCall = duckFactory.createDuckCall();
QuackableInterfaceForCompoundPattern rubberDuck = duckFactory.createRubberDuck();
QuackableInterfaceForCompoundPattern gooseDuck = new GooseAdapter(new Goose());
// System.out.println("\n오리 시뮬레이션 게임: 무리 (+ 컴포지트)");
Flock flockOfDucks = new Flock();
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
flockOfDucks.add(gooseDuck);
//물오리만 들어가는 Flock객체(Composite객체) 생성
Flock flockOfMallards = new Flock();
//개별 물오리(mallard) 생성
QuackableInterfaceForCompoundPattern mallardOne = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardTwo = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardThree = duckFactory.createMallardDuck();
QuackableInterfaceForCompoundPattern mallardFour = duckFactory.createMallardDuck();
//개별 물오리를 컴포지트 객체에 추가하기
flockOfMallards.add(mallardOne);
flockOfMallards.add(mallardTwo);
flockOfMallards.add(mallardThree);
flockOfMallards.add(mallardFour);
//물오리 무리(flockOfMallards)를 아까 만든 오리 무리(flockOfDucks)에 넣는다.
flockOfDucks.add(flockOfMallards);
System.out.println("\n오리 시뮬레이션 게임 (+옵저버))");
Quackologist quackologist = new Quackologist();
flockOfDucks.registerObserver(quackologist);
simulate(flockOfDucks);
System.out.println("오리가 소리 낸 횟수:" +
QuackCountingDecorator.getQuacks() + " 번");
}
//데코레이터도 QuackableInterfaceForCompoundPatter 인터페이스이다.
void simulate(QuackableInterfaceForCompoundPattern duck){
duck.quack();
}
}
/*
꽥꽥
꽥꽥학자: com.example.designpatternstudy.compoundPattern.RedheadDuck@466276d8 가 방금 소리냈다.
꽉꽉
꽥꽥학자: com.example.designpatternstudy.compoundPattern.DuckCall@5ce8d869 가 방금 소리냈다.
삑삑
꽥꽥학자: com.example.designpatternstudy.compoundPattern.RubberDuck@27eedb64 가 방금 소리냈다.
끽끽
꽥꽥
꽥꽥학자: com.example.designpatternstudy.compoundPattern.MallardDuck@64c63c79 가 방금 소리냈다.
꽥꽥
꽥꽥학자: com.example.designpatternstudy.compoundPattern.MallardDuck@31c7528f 가 방금 소리냈다.
꽥꽥
꽥꽥학자: com.example.designpatternstudy.compoundPattern.MallardDuck@2b76ff4e 가 방금 소리냈다.
꽥꽥
꽥꽥학자: com.example.designpatternstudy.compoundPattern.MallardDuck@7a1234bf 가 방금 소리냈다.
오리가 소리 낸 횟수:7 번
*/
7. 클래스 다이어그램
'Design Pattern > Compound Pattern' 카테고리의 다른 글
Compound Pattern: 5. Observer 패턴 (0) | 2022.11.03 |
---|---|
Compound Pattern: 4. Composite 패턴 + Iterator패턴 (0) | 2022.10.31 |
Compound Pattern: 3. Factory 패턴 (0) | 2022.10.15 |
Compound Pattern: 2. Decorator 패턴 추가 (0) | 2022.10.14 |
Compound Pattern: 1. Adapter패턴 (0) | 2022.10.14 |