2015년 9월 22일 화요일

클래스 디자인 패턴 12. Compound Pattern (복습)

1. 스트리티지 패턴 적용(일부만)
    처음 진행했던 duck 예제를 처음부터 작성합니다.
    하나의 인터페이스를 두어 행동 active 에 대해서
      다른 동작을 하고 이를 수정코저 할때 그 부분만
      수정할 수 있도록 떼어 냈습니다.

   다이어그램은 아래와 같습니다.
     행동 quackable 를 4개 클래스가 implements 하고 있습니다.




  1) Quackable  interface 작성
package quackable_1;

public interface Quackable {
public void quack();
}


  2) Quackabel 기능을 상속받은 다른 구현체들을 작성
    (1) 
package quackable_1;

public class MallardDuck implements Quackable {

@Override
public void quack() {
System.out.println("Quack Quack * 3");

}

}


    (2)

package quackable_1;

public class RedheadDuck implements Quackable {

@Override
public void quack() {
System.out.println("Quack * 2");

}

}

    (3) 
package quackable_1;

public class DuckCall implements Quackable {

@Override
public void quack() {
System.out.println("Kwak");
}

}


    (4) 

package quackable_1;

public class RubberDuck implements Quackable {

@Override
public void quack() {
System.out.println("Squeak");
}

}

  3) test 구현체 작성
package simulator;

import quackable_1.DuckCall;
import quackable_1.MallardDuck;
import quackable_1.Quackable;
import quackable_1.RedheadDuck;
import quackable_1.RubberDuck;

public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}

private void simulate() {
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck();
Quackable duckCall = new DuckCall();
Quackable rubberDuck = new RubberDuck();
System.out.println("\n Duck Simulator");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
}

private void simulate(Quackable duck) {
duck.quack();
}
}

1차 실행 결과 :




2. 어댑터 패턴
    여기에 비슷한 기능을 하지만 엄연이 다른 메서드를
      보유하고 있는 '거위' 라는 클래스를 생성합니다.
    하지만 여기 실행에 포함하고 싶습니다.
     구별없이 진행하려면 거위 클래스에 어댑터를 달아서
     duck와 구별 없이 동작하도록 변경합니다.




  1) 거위 클래스 작성 이는 interface를 참고하지 않는
       duck 계열과는 다른 클래스 입니다.

package honkable_2;

public class Goose {
public void honk(){
System.out.println("----Honk im honk honk honk----");
}
}

  2) Goose를 duck처럼 동작하기 위해서 adapter를 생성합니다.
package adapterQuack_3;

import honkable_2.Goose;
import quackable_1.Quackable;

public class GooseAdapter implements Quackable{
Goose goose ;

public GooseAdapter(Goose goose){
this.goose=goose;
}

@Override
public void quack() {
goose.honk();
}
}


  3) 정상적으로 동작하는지 보기 위해 test 소스를 수정합니다.
      중요한 부분은 인스턴스 생성시 어댑터를 통해서 goose를
      생성하였다는 점이며 이후 동일한 메서드를 통해서
      goose의 honk() 메서드를 실행할 수 있었습니다.
Quackable gooseDuck = new GooseAdapter(new Goose());
simulate(gooseDuck);


package simulator;

import honkable_2.Goose;
import adapterQuack_3.GooseAdapter;
import quackable_1.DuckCall;
import quackable_1.MallardDuck;
import quackable_1.Quackable;
import quackable_1.RedheadDuck;
import quackable_1.RubberDuck;

public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}

private void simulate() {
Quackable mallardDuck =new MallardDuck();
Quackable redheadDuck = new RedheadDuck();
Quackable duckCall = new DuckCall();
Quackable rubberDuck = new RubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\n Duck Simulator");

simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);
}

private void simulate(Quackable duck) {
duck.quack();
}
}

2번까지 진행 결과


3. 데코레이터 패턴
    오리울음 횟수를 체크하는 counter 를 추가하고자 합니다.
      이를 위해서 오리 생성자를 다른 객체로 감싸서
      기존 기능을 + count 를 할 수 있는 기능을 추가합니다.

    추가 내용에 대한 다이어그램은 아래와 같습니다.



  1) QuackAble를 참고하는 QuackCount를 생성합니다.
       여기서는 quack 를 구현할때 count를 체크하게끔하고
       count는 static 선언하여 인스턴트와 상관없이
       count가 쌓이게끔 합니다.
     추가로 getQuacks에서 count를 반환하도록 작성합니다.

package quackCountDeco_4;

import quackable_1.Quackable;

public class QuackCount implements Quackable {
Quackable duck;
static int numberofQuacks;

public QuackCount(Quackable duck) {
this.duck = duck;
}

@Override
public void quack() {
duck.quack();
numberofQuacks++;
}

public static int getQuacks(){
return numberofQuacks;
}
}


  2) 테스트 코드를 수정합니다. 여기서 각 duck 인스턴스 생성시
      가자의 구현체를 QuackCount 객체에 넣어서 생성합니다.
new QuackCount(new MallardDuck());

package simulator;

import honkable_2.Goose;
import adapterQuack_3.GooseAdapter;
import quackCountDeco_4.QuackCount;
import quackable_1.DuckCall;
import quackable_1.MallardDuck;
import quackable_1.Quackable;
import quackable_1.RedheadDuck;
import quackable_1.RubberDuck;

public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}

private void simulate() {
Quackable mallardDuck = new QuackCount(new MallardDuck());
Quackable redheadDuck = new QuackCount(new RedheadDuck());
Quackable duckCall = new QuackCount(new DuckCall());
Quackable rubberDuck = new QuackCount(new RubberDuck());
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\n Duck Simulator");

simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);

System.out.println("The Duck quacked "+ QuackCount.getQuacks()+"times.");
}

private void simulate(Quackable duck) {
duck.quack();
}
}

3번까지 진행 결과 : 


4. 팩토리 패턴
    오리 생성하는 부분을 따로 떼어서 팩토리로 감싸는걸 생각해봅니다.
      이렇게 하면 다른 비슷한 클래스를 추가할때 공통 부분을
      건들지 않고 팩토리만 수정하면 추가되며
      사용 하는 부분은 test 부분에서 수정하도록 일부 떼어내기가 가능
      해집니다.
 
     구현하고자  하는 팩토리 패턴의 다이어그램입니다.



  1) DuckFactory 작성을 위한 추상 클래스를 하나 작성합니다.
      여기에 오리를 추가하면 구현부에 오류가 뜨기 때문에 쉽게
      구현이 가능합니다.

package duckFactory_5;

import quackable_1.Quackable;

public abstract class AbstractDuckFactory {
public abstract Quackable createMallarDuck();
public abstract Quackable createRedheadDuck();
public abstract Quackable createDuckCall();
public abstract Quackable createRubberDuck();
}


  2)  DuckFacotry를 상속받아 구현체인 CountDuckFacory를
       구현합니다. 이때 QuackCounter 도 포함하여 구현토록
        작성합니다.

package duckFactory_5;

import quackCountDeco_4.QuackCount;
import quackable_1.DuckCall;
import quackable_1.MallardDuck;
import quackable_1.Quackable;
import quackable_1.RedheadDuck;
import quackable_1.RubberDuck;

public class CountingDuckFactory extends AbstractDuckFactory {

@Override
public Quackable createMallarDuck() {
// TODO Auto-generated method stub
return new QuackCount(new MallardDuck());
}

@Override
public Quackable createRedheadDuck() {
// TODO Auto-generated method stub
return new QuackCount(new RedheadDuck());
}

@Override
public Quackable createDuckCall() {
// TODO Auto-generated method stub
return new QuackCount(new DuckCall());
}

@Override
public Quackable createRubberDuck() {
// TODO Auto-generated method stub
return new QuackCount(new RubberDuck());
}

}


  3) 여기에 맞춰 테스트 코드를 수정합니다.
package simulator;

import duckFactory_5.AbstractDuckFactory;
import duckFactory_5.CountingDuckFactory;
import honkable_2.Goose;
import adapterQuack_3.GooseAdapter;
import quackCountDeco_4.QuackCount;
import quackable_1.DuckCall;
import quackable_1.MallardDuck;
import quackable_1.Quackable;
import quackable_1.RedheadDuck;
import quackable_1.RubberDuck;

public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();

simulator.simulate(duckFactory);
}

private void simulate(AbstractDuckFactory duckFactory) {

Quackable mallardDuck = duckFactory.createMallarDuck();
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\n Duck Simulator");

simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);

System.out.println("The Duck quacked "+ QuackCount.getQuacks()+"times.");

}

private void simulate(Quackable duck) {
duck.quack();
}
}


4번까지 진행 결과 : 3번 항목과 일치합니다.


5. 컴포지트 패턴+이터레이터 패턴
    오리를 하나씩 생성하는데 그부분이 눈에 거슬립니다.
      굳이 한 객체씩 관리해야 하는 점 때문입니다.
    Iterator에 객체 생성부분을 통합시키고 array로만
      해당 부분을 관리하면 simulator를 한번만
      돌릴 수 있습니다.
    그리고 오리나 거위나 상관없이 add 함수만으로 객체를
      simulator 상에 추가할 수 있습니다.

     구현하고자  하는 팩토리 패턴의 다이어그램입니다.



  1) Iterator 를 생성합니다.
package iterator_6;

import java.util.ArrayList;
import java.util.Iterator;

import quackable_1.Quackable;

public class Flock implements Quackable{
ArrayList quackers = new ArrayList();

public void add(Quackable quacker){
quackers.add(quacker);
}

@Override
public void quack() {
Iterator iterator = quackers.iterator();
while(iterator.hasNext()){
Quackable quacker = (Quackable) iterator.next();
quacker.quack();
}
}
}


  2) 테스트 코드를 수정합니다.

package simulator;

import iterator_6.Flock;
import duckFactory_5.AbstractDuckFactory;
import duckFactory_5.CountingDuckFactory;
import honkable_2.Goose;
import adapterQuack_3.GooseAdapter;
import quackCountDeco_4.QuackCount;
import quackable_1.Quackable;

public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulate(duckFactory);
}

private void simulate(AbstractDuckFactory duckFactory) {

Quackable mallardDuck = duckFactory.createMallarDuck();
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\n Duck Simulator");

Flock flockOfCucks = new Flock();

flockOfCucks.add(mallardDuck);
flockOfCucks.add(redheadDuck);
flockOfCucks.add(duckCall);
flockOfCucks.add(rubberDuck);
flockOfCucks.add(gooseDuck);

simulate(flockOfCucks);
System.out.println("The Duck quacked "+ QuackCount.getQuacks()+"times.");
}

private void simulate(Quackable duck) {
duck.quack();
}
}


5번까지 진행 결과 : 3,4번 결과와 동일합니다.

댓글 없음:

댓글 쓰기