Java

[Design Pattern] 추상적인 공장 패턴(Abstract Factory Pattern)

구루싸 2020. 6. 21. 16:33
반응형
SMALL

어느덧 6월도 끝나가네요-_-

올해 여름은 코로나19로 인해서

제대로된 휴가는 물 건너 간거 같고

방콕이나 해야할 것 같습니다ㅜㅜ

아무튼 오늘의 학습 주제는

추상적인 공장 패턴입니다

추상적인 공장 패턴에 등장하는

역할들을 정리해보면 다음과 같습니다

역할 설명
추상적인 제품(Abstract Product) Abstract Factory 역할에 의해 만들어지는 추상적인 부품이나 제품의 인터페이스를 결정
추상적인 공장(Abstract Factory) Abstract Product 역할의 인스턴스를 만들어 내기 위한 인터페이스를 결정
의뢰자(Client) Abstract Factory 역할과 Abstract Product 역할의 인터페이스만을 사용해서 주어진 역할을 실행
구체적인 제품(Concrete Product) Abstract Product 역할의 인터페이스를 구현
구체적인 공장(Concrete Factory) Abstract Factory 역할의 인터페이스를 구현

언제나 처럼 이 표만 가지고는

뭔지 감이 잘 안오네요-_-

그럼 구현을 해보겠습니다

1. 추상 클래스(Abstract Class) Factory.java

package abstractFactoryPattern.factory;

public abstract class Factory {
	public static Factory getFactory(String classname) {
		Factory factory = null;
		try {
			factory = (Factory)Class.forName(classname).newInstance();
		} catch(ClassNotFoundException e) {
			System.out.println("Class " + classname + "is not founded");
		} catch(Exception e) {
			e.printStackTrace();
		}
		return factory;
	}
	public abstract Link createLink(String caption, String url);
	public abstract Tray createTray(String caption);
	public abstract Page createPage(String title, String author);
}

2. 추상 클래스(Abstract Class) Item.java

package abstractFactoryPattern.factory;

public abstract class Item {
	protected String caption;
	public Item(String caption) {
		this.caption = caption;
	}
	public abstract String makeHTML();
}

3. 추상 클래스(Abstract Class) Link.java

package abstractFactoryPattern.factory;

public abstract class Link extends Item {
	protected String url;
	public Link(String caption, String url) {
		super(caption);
		this.url = url;
	}
}

4. 추상 클래스(Abstract Class) Page.java

package abstractFactoryPattern.factory;
import java.io.*;
import java.util.*;
public abstract class Page {
	protected String title;
	protected String author;
	protected ArrayList<Item> content = new ArrayList<Item>();
	public Page(String title, String author) {
		this.title = title;
		this.author = author;
	}
	public void add(Item item) {
		content.add(item);
	}
	public void output() {
		try {
			String filename = title + ".html";
			Writer writer = new FileWriter(filename);
			writer.write(this.makeHTML());
			writer.close();
			System.out.println("Writed " + filename);
		} catch(IOException e) {
			e.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	public abstract String makeHTML();
}

5. 추상 클래스(Abstract Class) Tray.java

package abstractFactoryPattern.factory;
import java.util.*;
public abstract class Tray extends Item {
	protected ArrayList<Item> tray = new ArrayList<Item>();
	public Tray(String caption) {
		super(caption);
	}
	public void add(Item item) {
		tray.add(item);
	}
}

6. 클래스(Class) ListFactory.java

package abstractFactoryPattern.listfactory;
import abstractFactoryPattern.factory.*;
public class ListFactory extends Factory {
	public Link createLink(String caption, String url) {
		return new ListLink(caption, url);
	}
	public Tray createTray(String caption) {
		return new ListTray(caption);
	}
	public Page createPage(String title, String author) {
		return new ListPage(title, author);
	}
}

7. 클래스(Class) ListLink.java

package abstractFactoryPattern.listfactory;
import abstractFactoryPattern.factory.*;
public class ListLink extends Link {
	public ListLink(String caption, String url) {
		super(caption, url);
	}
	public String makeHTML() {
		return " <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
	}
}

8. 클래스(Class) ListPage.java

package abstractFactoryPattern.listfactory;
import abstractFactoryPattern.factory.*;
import java.util.Iterator;
public class ListPage extends Page {
	public ListPage(String title, String author) {
		super(title, author);
	}
	public String makeHTML() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("<html><head><title>" + title + "</title></head>\n");
		buffer.append("<body>\n");
		buffer.append("<h1>" + title + "</h1>\n");
		buffer.append("<ul>\n");
		Iterator<Item> it = content.iterator();
		while(it.hasNext()) {
			Item item = (Item)it.next();
			buffer.append(item.makeHTML());
		}
		buffer.append("</ul>\n");
		buffer.append("<hr><address>" + author + "</address>");
		buffer.append("</body></html>\n");
		return buffer.toString();
	}
}

9. 클래스(Class) ListTray.java

package abstractFactoryPattern.listfactory;
import abstractFactoryPattern.factory.*;
import java.util.Iterator;
public class ListTray extends Tray {
	public ListTray(String caption) {
		super(caption);
	}
	public String makeHTML() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("<li>\n");
		buffer.append(caption + "\n");
		buffer.append("<ul>\n");
		Iterator<Item> it = tray.iterator();
		while(it.hasNext()) {
			Item item = (Item)it.next();
			buffer.append(item.makeHTML());
		}
		buffer.append("</ul>\n");
		buffer.append("</li>\n");
		return buffer.toString();
	}
}

10. 클래스(Class) Test.java

import abstractFactoryPattern.factory.*;
public class Test {
	public static void main(String[] args) {
		/* Abstract Factory Pattern */
		Factory factory = Factory.getFactory("abstractFactoryPattern.tablefactory.TableFactory");
		
		Link joins = factory.createLink("중앙일보", "https://joongang.joins.com/");
		Link chosun = factory.createLink("조선일보", "http://www.chosun.com/");
		Link naver = factory.createLink("Naver", "https://www.naver.com/");
		Link google = factory.createLink("Google", "https://www.google.com/");
		
		Tray traynews = factory.createTray("신문");
		traynews.add(joins);
		traynews.add(chosun);
		
		Tray traysearch = factory.createTray("검색엔진");
		traysearch.add(naver);
		traysearch.add(google);
		
		Page page = factory.createPage("LinkPage", "GuruSa");
		page.add(traynews);
		page.add(traysearch);
		page.output();
	}
}

위의 코드에서

factory 패키지에 속한 추상 클래스들이

추상적인 공장과 제품의 역할을 수행하고

listfactory 패키지에 속한 클래스들이

구체적인 공장과 제품의 역할을 수행합니다

새로운 공장을 추가하려면

어떻게 하면 될까요?

아래와 같이

구체적인 공장을 새로 추가해보겠습니다

11. 클래스(Class) TableFactory.java

package abstractFactoryPattern.tablefactory;
import abstractFactoryPattern.factory.*;
public class TableFactory extends Factory {
	public Link createLink(String caption, String url) {
		return new TableLink(caption, url);
	}
	public Tray createTray(String caption) {
		return new TableTray(caption);
	}
	public Page createPage(String title, String author) {
		return new TablePage(title, author);
	}
}

12. 클래스(Class) TableLink.java

package abstractFactoryPattern.tablefactory;
import abstractFactoryPattern.factory.*;
public class TableLink extends Link {
	public TableLink(String caption, String url) {
		super(caption, url);
	}
	public String makeHTML() {
		return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";
	}
}

13. 클래스(Class) TablePage.java

package abstractFactoryPattern.tablefactory;
import abstractFactoryPattern.factory.*;
import java.util.*;
public class TablePage extends Page {
	public TablePage(String title, String author) {
		super(title, author);
	}
	public String makeHTML() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("<html><head><title>" + title + "</title></head>\n");
		buffer.append("<body>\n");
		buffer.append("<h1>" + title + "</h1>\n");
		buffer.append("<table width = \"80%\" border=\"3\">\n");
		Iterator<Item> it = content.iterator();
		while(it.hasNext()) {
			Item item = (Item)it.next();
			buffer.append("<tr>" + item.makeHTML() + "</tr>");
		}
		buffer.append("</table>\n");
		buffer.append("<hr><address>" + author + "</address>");
		buffer.append("</body></html>\n");
		return buffer.toString();
	}
}

14. 클래스(Class) TableTray.java

package abstractFactoryPattern.tablefactory;
import abstractFactoryPattern.factory.*;
import java.util.*;
public class TableTray extends Tray {
	public TableTray(String caption) {
		super(caption);
	}
	public String makeHTML() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("<td>");
		buffer.append("<table width=\"100%\" border=\"1\"><tr>");
		buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
		buffer.append("</tr>\n");
		buffer.append("<tr>\n");
		Iterator<Item> it = tray.iterator();
		while ( it.hasNext() ) {
			Item item = (Item)it.next();
			buffer.append(item.makeHTML());
		}
		buffer.append("</tr></table>");
		buffer.append("</td>");
		return buffer.toString();
	}
}

보시면 새로운 공장을 추가할 때

factory 패키지의 클래스가 가지고 있는

추상적인 부분을 구체화 해가는 일입니다

이 때 아무리 구체적인 공장을 추가하거나

버그를 수정한다고 하더라도

추상적인 공장이나 Test 클래스를

수정할 필요가 없습니다

그런데 만약 공장이 아니라

새로운 부품을 추가한다고 하면

factory 패키지에 수정이 필요하므로

좀 난감한 상황이 되겠네요-_-

또 위의 코드에서

인스턴스를 생성하는 방법을 보시면

java.lang.Class 클래스의

newInstance 메소드를 이용하고 있습니다

이 메소드는 InstantiationException 혹은

IllegalAccessException을 예외로 제공해

예외처리를 해주어야합니다

지난 프로토 타입 패턴(prototype pattern)에서

이용한 clone도 다시 한 번 상기 시켜보면서

오늘의 학습은 여기서 마치겠습니다

프로토 타입 패턴이 궁금하시다면

아래의 링크↓

2020/06/14 - [Java] - [Design Pattern] 싱글톤(Singleton) 패턴과 프로토타입(Prototype) 패턴

 

[Design Pattern] 싱글톤(Singleton) 패턴과 프로토타입(Prototype) 패턴

어느 덧 한 주를 마무리하는 일요일이 되었습니다 내일이 되면 다시 한주를 바쁘게 살아가야한다는... 아무튼 오늘은 지정한 클래스의 인스턴스가 한 개만 존재하는 것을 보증하고 싶을 때 사용

yssa.tistory.com

그럼 이만-_-

 

반응형
LIST