본문 바로가기

Coding Note

[Design pattern] Abstract Factory

Factory Pattern 에는 크게 두가지, Abstract factory pattern과 Factory method pattern 로 나뉜다.


뭐가됬든간에 Factory라는 단어가 설명하듯, Factory pattern은 인스턴스의 생성과정을 숨긴채, 다 만들어진 인스턴스를 반환해주는 역할을 한다. 때문에 Factory pattern은 대체로 생성과정에 여러가지 작업을 해줘야하는 상황에 사용된다.

 

(기본적인 Factory pattern 클래스 관계도)

 

Factory pattern에서 중요한점은 생성할 객체의 추상화에 있다.(abstract 키워드를 말하는게 아니다.) 생성과정에서 추상화된 객체를 반환하게 하여 상속받는 모든 자식클래스를 다루게된다.즉, 생성과정의 변화에 관계없이 프로그래밍을 가능하게하며 생성과정을 캡슐화하여 외부에 노출을 줄이게된다. 그리고 코드의 확장성을 크게하여 새롭게 추가되는 기능에 유연하게 대처할 수 있게해준다. 그리고 코드의 커플링을 낮추어 코드 유지차원에서도 효과를 톡톡히 볼 수 있다.

 

물론 공장을 세우기위한 노력과 어떻게 해야 좀 더 유연한 코드를 만들까 하는 고뇌는 뒤따라오겠지만 이런 고뇌후의 코드는 아름답기 마련이다.



두 종류중 하나인 Abstract factory pattern에 대해서 먼저 알아보자.


Abstract Factory Pattern : Factory를 추상화하여 객체의 생성과정을 사용하는측에서 결정할 수 있게한 패턴. Strategy pattern과 결합된 형태라고 생각된다.

 

 

Abstract factory pattern을 사용하면 Strategy pattern을 사용할때처럼 큰 유연성을 가져다준다. 생성루틴을 확장할 수 있고, 프로그램 실행중에도 다이나믹하게 생성루틴을 갈아낄 수 있다. 그럼에도 사용하는 측의 코드에 전혀 영향이 가지 않는다는게 최대의 장점이다.


하지만 코드의 양이 많아지고 객체를 생성하기까지 다소 복잡한 과정을 거쳐야한다. 생성 과정에 규모가 작다면 오히려 코드의 이해도를 떨어뜨리는 패턴이 될 가능성을 가지고 있으니 신중하게 생각해서 적용해야한다.



스킬 시스템으로 간단한 예를 들어보자. 캐릭터의 직업엔 여러가지가있다. 그런데 기술을 '배운다'는 과정은 어떤 직업이건 같은 행동일 것이다. 이런상황에 Abstract factory pattern을 적용하여 객체지향적인 구조를 설계할 수 있다.


/* Skill.java */

public interface Skill {

public abstract void use();

}


/* MagicMissile.java */

public class MagicMissile implements Skill {

@Override

public void use(){

System.out.println("Cast Magic missile");

}

}


/* FireBall.java */

public class FireBall implements Skill {

@Override

public void use() {

System.out.println("Cast Fire ball");

}

}


/* AbstractSkillFactory.java */

public abstract class AbstractSkillFactory {

public abstract Skill createSkill(String skillName);

}


/* MagicSkillFactory.java */

public class MagicSkillFactory extends AbstractSkillFactory {

@Override

public Skill createSkill(String skillName) {

Skill skill = null;


skillName.toLowerCase();

if(skillName.equals("magicmissile")){

skill = new MagicMissile();

}

else if(skillName.equals("fireball")){

skill = new FireBall();

}


return skill;

}

}


/* SwordSkillFactory.java */

public class SwordSkillFactory extends AbstractSkillFactory {

@Override

public Skill createSkill(String skillName) {

Skill skill = null;


skillName.toLowerCase();

if(skillName.equals("whirlwind")){

skill = new Whirlwind();

}

else if(skillName.equals("bash")){

skill = new Bash();

}


return skill;

}

}



/* Character.java */

public class Character {

private AbstractSkillFactory skillFactory;

private Collection<Skill> skills = new Collection<Skill>();

 

public void setSkillFactory(AbstractSkillFactory newSkillFactory){

skillFactory = newSkillFactory;

}

 

//어떤 직업이건 스킬을 배우는입장은 변함없다.

public void runSkill(String skillName){

Skill skill = skillFactory.createSkill(skillName);

// skill에 대한 세팅

skills.add( skill );

}


public void useSkill(int index){

skills.at(index).use();

}

}



/* main */

public static void main(String[] args){

Character character = new Character();


character.setSkillFactory(new MagicSkillFactory());

character.runSkill("magicmissile");

character.useSkill();


//다른직업의 스킬을 배우자

character.setSkillFactory(new SwordSkillFactory());

character.runSkill("bash");

character.useSkill();

}


스킬을 배우는 부분에서 스킬 생성기가 바뀌는데, 스킬을 배우는 부분의 구현은 변함이 없다. 여기서 abstract factory 의 큰 확장성을 볼 수 있다.

 

한줄요약 : Abstract factory pattern은 Strategy 와 Factory의 콜라보. 전략적인 공장이다.

'Coding Note' 카테고리의 다른 글

[Design pattern] Singleton  (0) 2013.01.31
[Design pattern] Factory Method  (0) 2013.01.30
[Design pattern] Observer  (4) 2013.01.22
[Design pattern] Strategy  (0) 2013.01.19
[ExtJs4] nested model  (0) 2013.01.01