[GoF] Abstract Factory 패턴

패턴명칭

Abstract Factory

필요한 상황

어떤 기능 또는 출력결과를 생성할때 그 기능 또는 출력결과를 구성하는 각각의 요소를 생성하는 방법을 추상화할 수 있는 패턴이다.

예제 코드

Factory는 어떤 기능이나 출력결과를 생성하기 위해 구성되는 각각의 요소를 생성하는 구체적인 클래슬르 생성하는 클래스이다. Member와 Club 그리고 Page가 각각의 요소에 대한 추상 클래스이다. Item 추상 클래스는 Member와 Club을 같은 개념으로 다루기 위해 존재한다. 실제 기능 또는 출력결과를 생성하는 구체 클래스는 HtmlMember, HtmlClub, htmlPage 그리고 HtmlFactory이다.

Factory 클래스를 먼저 보자

package tstThread;

public abstract class Factory {
	public abstract Member createMember(String name, String duty, String email);
	public abstract Club createClub(String title);
	public abstract Page createPage(String title, String footer);
}

Factory 클래스는 Member, Club, Page 객체를 생성한다. Member와 Club은 동일한 개념으로 취급되기 위해 Item이라는 추상클래스를 상속받는데 다음과 같다.

package tstThread;

public abstract class Item {
	protected String name;
	
	public Item(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public abstract String getResult();
}

이 Item 클래스를 상속받는 Member 클래스는 다음과 같다.

package tstThread;

public abstract class Member extends Item {
	private String duty;
	private String email;
	
	public Member(String name, String duty, String email) {
		super(name);
		this.duty = duty;
		this.email = email;
	}
	
	public String getDuty() {
		return duty;
	}
	
	public String getEmail() {
		return email;
	}
}

Item을 상속받는 Club 클래스는 다음과 같다.

package tstThread;

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

public abstract class Club extends Item {
	private ArrayList<Item> items = new ArrayList<Item>();
	public Club(String name) {
		super(name);
	}
	
	public void add(Item item) {
		items.add(item);
	}

	public Iterator getIterator() {
		return items.iterator();
	}
}

Page 클래스는 다음과 같다.

package tstThread;

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

public abstract class Page {
	private String title;
	private String footer;	
	private ArrayList<Item> items = new ArrayList<Item>();
	
	public Page(String title, String footer) {
		this.title = title;
		this.footer = footer;
	}
	
	public void add(Item item) {
		items.add(item);
	}
	
	public String getTitle() {
		return this.title;
	}
	
	public String getFooter() {
		return this.footer;
	}
	
	public Iterator getIterator() {
		return items.iterator();
	}
	
	public abstract String getResult();
}

이제 구체적인 부품에 해당하는 클래스들을 살펴보자. 먼저 Member의 파생 클래스인 HtmlMember이다.

package tstThread;

public class HtmlMember extends Member {

	public HtmlMember(String name, String duty, String email) {
		super(name, duty, email);
	}

	@Override
	public String getResult() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("
    "); sb.append("
  • Name: "); sb.append(this.getName()); sb.append("
  • "); sb.append("
      "); sb.append("
    • Duty: "); sb.append(this.getDuty()); sb.append("
    • "); sb.append("
    • Email: "); sb.append(this.getEmail()); sb.append("
    • "); sb.append("
    "); sb.append("
"); return sb.toString(); } }

다음은 Club의 파생 클래스인 HtmlClub이다.

package tstThread;

import java.util.Iterator;

public class HtmlClub extends Club {
	public HtmlClub(String name) {
		super(name);
	}

	@Override
	public String getResult() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("
    "); sb.append("
  • Club Name: "); sb.append(getName()); sb.append("
  • "); Iterator iter = getIterator(); while(iter.hasNext()) { Item item = iter.next(); sb.append(item.getResult()); } sb.append("
"); return sb.toString(); } }

다음은 Page의 파생 클래스인 HtmlPage이다.

package tstThread;

import java.util.Iterator;

public class HtmlPage extends Page {
	public HtmlPage(String title, String footer) {
		super(title, footer);
	}

	@Override
	public String getResult() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("");
		sb.append("

"); sb.append(getTitle()); sb.append("

"); Iterator iter = getIterator(); while(iter.hasNext()) { Item item = iter.next(); sb.append(item.getResult()); } sb.append("
"); sb.append(""); sb.append(getFooter()); sb.append(""); sb.append(""); return sb.toString(); } }

다음은 Factory의 파생 클래스인 HtmlFactory이다.

package tstThread;

public class HtmlFactory extends Factory {

	@Override
	public Member createMember(String name, String duty, String email) {
		return new HtmlMember(name, duty, email);
	}

	@Override
	public Club createClub(String title) {
		return new HtmlClub(title);
	}

	@Override
	public Page createPage(String title, String footer) {
		return new HtmlPage(title, footer);
	}
}

지금까지의 클래스들을 사용하는 예제 코드는 다음과 같다.

package tstThread;

public class Main {
	public static void main(String[] args) {
		Page page = new HtmlPage("OrangeTree", "since 2021");
		Factory factory = new HtmlFactory();
		
		Member ceo = factory.createMember("Jany", "CEO", "jany@orangetree.com");
		page.add(ceo);
		
		Club club1 = factory.createClub("GAME");
		Member mem1_club1 = factory.createMember("Toms", "Manager", "toms@orangetree.com");
		Member mem2_club1 = factory.createMember("Sujin", "Assist", "sujin@orangetree.com");
		
		club1.add(mem1_club1);
		club1.add(mem2_club1);
		page.add(club1);
		
		Club club2 = factory.createClub("STUDY");
		Member mem1_club2 = factory.createMember("Jack", "Manager", "jack@orangetree.com");
		Member mem2_club2 = factory.createMember("Robert", "Assist", "robert@orangetree.com");
		club2.add(mem1_club2);
		club2.add(mem2_club2);
		page.add(club2);

		System.out.println(page.getResult());
	}
}

실행 결과는 HTML 출력인데, 이를 웹브라우저에서 보면 다음과 같다.

이 글은 소프트웨어 설계의 기반이 되는 GoF의 디자인패턴에 대한 강의자료입니다. 완전한 실습을 위해 이 글에서 소개하는 클래스 다이어그램과 예제 코드는 완전하게 실행되도록 제공되지만, 상대적으로 예제 코드와 관련된 설명이 함축적으로 제공되고 있습니다. 이 글에 대해 궁금한 점이 있으면 댓글을 통해 남겨주시기 바랍니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다