일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- IntelliJ
- linux
- laravel
- Oracle
- Gradle
- Web Server
- 요리
- springboot
- JVM
- ReactJS
- php
- tool
- Design Patterns
- it
- devops
- java
- AWS
- 맛집
- MySQL
- jsp
- jenkins
- db
- redis
- Spring Batch
- elasticsearch
- Spring
- javascript
- Git
- Spring Boot
- ubuntu
- Today
- Total
아무거나
[Design Pattern] Abstract Factory Pattern 본문
추상 팩토리 패턴(Abstract Factory Pattern)
인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있다.
제품군을 만들 때를 예로 들어보자.
추상 팩토리 패턴
을 사용하면 클라이언트에서 추상 인터페이스를 통하여 일련의 제품들을 공급받을 수 있다. 실제로 어떤 제품이 생산되는지도 전혀 알 필요가 없다. 따라서 클라이언트와 팩토리에서 생산되는 제품을 분리시킬 수 있다.
- AbstractFactory: 모든 구상 팩토리에서 구현해야 하는 인터페이스이다. 제품을 생산하기 위한 일련의 메소드들이 정의되어 있다.
- ConcreteFactory1~2: 구상 팩토리에서는 서로 다른 제품군을 구현한다. 클라이언트에서 제품이 필요하면 이 팩토리 가운데 적당한걸 선택하여 쓰면 되기 때문에 제품 객체의 인스턴스를 직접 만들 필요가 없다.
- Client: 클라이언트를 만들 때는 추상 팩토리를 바탕으로 만든다. 실제 팩토리는 실행시에 결정된다.
- AbstractProductA~B: 제품군 각 구상 팩토리에서 필요한 제품들을 모두 만들 수 있다.
아마 이렇게 설명을 보면 이해가 안 될 것이다. 실습을 통해 이해하자.
추상 팩토리 패턴 예시 - 1
자전거 부품들을 생산하는 공장(=Factory)을 예시로 만들어보자.
abst 패키지를 생성하고 자전거의 부품들과 팩토리를 생성
[Body.java]
package com.bkjeon.abstract_factory.abst;
public interface Body {}
[Wheel.java]
package com.bkjeon.abstract_factory.abst;
public interface Wheel {}
[BikeFactory.java]
package com.bkjeon.abstract_factory.abst;
public interface BikeFactory {
public Body createBody();
public Wheel creatWheel();
}
bong 패키지를 생성(자전거 메이커 관련 패키지) 후 각각의부품 구현
[BongBody.java]
package com.bkjeon.abstract_factory.bong;
import com.bkjeon.abstract_factory.abst.Body;
public class BongBody implements Body {}
[BongWheel.java]
package com.bkjeon.abstract_factory.bong;
import com.bkjeon.abstract_factory.abst.Wheel;
public class BongWheel implements Wheel {}
[BongFactory.java]
package com.bkjeon.abstract_factory.bong;
import com.bkjeon.abstract_factory.abst.BikeFactory;
import com.bkjeon.abstract_factory.abst.Body;
import com.bkjeon.abstract_factory.abst.Wheel;
public class BongFactory implements BikeFactory {
@Override
public Body createBody() {
return new BongBody();
}
@Override
public Wheel creatWheel() {
return new BongWheel();
}
}
메인 클래스를 구현하자.
[Main.java]
package com.bkjeon.abstract_factory;
import com.bkjeon.abstract_factory.abst.BikeFactory;
import com.bkjeon.abstract_factory.abst.Body;
import com.bkjeon.abstract_factory.abst.Wheel;
import com.bkjeon.abstract_factory.bong.BongFactory;
public class Main {
public static void main(String[] args) {
BikeFactory factory = new BongFactory();
Body body = factory.createBody();
Wheel wheel = factory.creatWheel();
System.out.println(body.getClass());
System.out.println(wheel.getClass());
}
}
실행결과
class com.bkjeon.abstract_factory.bong.BongBody
class com.bkjeon.abstract_factory.bong.BongWheel
실행하면 해당 클래스의 구조를 볼 수 있다. 왜 이렇게 하냐면 만약 자전거를 생성하려면 자전거를 만드는 공장이 필요하고 그 공장이 Bong인 것이다.
추가적으로 Keun이라는 하나의 공장을 더 만들어보자. 그러면 keun 패키지를 생성하고 bong패키지와 같은 구조로 생성해주자.
[KeunBody.java]
package com.bkjeon.abstract_factory.keun;
import com.bkjeon.abstract_factory.abst.Body;
public class KeunBody implements Body {}
[KeunWheel.java]
package com.bkjeon.abstract_factory.keun;
import com.bkjeon.abstract_factory.abst.Wheel;
public class KeunWheel implements Wheel {}
[KeunBikeFactory.java]
package com.bkjeon.abstract_factory.keun;
import com.bkjeon.abstract_factory.abst.BikeFactory;
import com.bkjeon.abstract_factory.abst.Body;
import com.bkjeon.abstract_factory.abst.Wheel;
public class KeunBikeFactory implements BikeFactory {
@Override
public Body createBody() {
return new KeunBody();
}
@Override
public Wheel creatWheel() {
return new KeunWheel();
}
}
메인 클래스를 수정하자.
[Main.java]
package com.bkjeon.abstract_factory;
import com.bkjeon.abstract_factory.abst.BikeFactory;
import com.bkjeon.abstract_factory.abst.Body;
import com.bkjeon.abstract_factory.abst.Wheel;
import com.bkjeon.abstract_factory.keun.KeunBikeFactory;
public class Main {
public static void main(String[] args) {
// BikeFactory factory = new BongFactory();
BikeFactory factory = new KeunBikeFactory();
Body body = factory.createBody();
Wheel wheel = factory.creatWheel();
System.out.println(body.getClass());
System.out.println(wheel.getClass());
}
}
실행결과
class com.bkjeon.abstract_factory.keun.KeunBody
class com.bkjeon.abstract_factory.keun.KeunWheel
이렇게 다양한 물건들을 한 가지의 팩토리로 묶어줘서 동일한 방식으로 생성할 수 있게 해주는것이 추상 팩토리 패턴이다.
추상 팩토리 패턴 예시 - 2
우선 추상적인 클래스가 있는 패키지인 abst와 구체적인 클래스가 모여있는 win이라는 패키지를 생성하자.
그 다음 GUI 관련 인터페이스를 생성하자.
[GuiFac.java]
package com.bkjeon.abstract_factory2.abst;
public interface GuiFac {
public Button createButton();
public TextArea createTextArea();
}
[Button.java]
package com.bkjeon.abstract_factory2.abst;
public interface Button {
public void click();
}
[TextArea.java]
package com.bkjeon.abstract_factory2.abst;
public interface TextArea {
public String getText();
}
그 다음은 GUI 환경에서 할 수 있는 OS의 네임인 패키지를 생성해보자.
- linux, mac, win(위에서 이미 생성해놓았다.)
먼저 linux 패키지에서 추상 객체들을 구체적인 클래스 객체로 만들어주자.
[LinuxGuiFac.java]
package com.bkjeon.abstract_factory2.linux;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class LinuxGuiFac implements GuiFac {
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public TextArea createTextArea() {
return new LinuxTextArea();
}
}
[LinuxButton.java]
package com.bkjeon.abstract_factory2.linux;
import com.bkjeon.abstract_factory2.abst.Button;
public class LinuxButton implements Button {
@Override
public void click() {
System.out.println("리눅스 버튼");
}
}
[LinuxTextArea.java]
package com.bkjeon.abstract_factory2.linux;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class LinuxTextArea implements TextArea {
@Override
public String getText() {
return "리눅스 텍스트 에어리어";
}
}
메인 클래스를 생성하자.
[Main.java]
package com.bkjeon.abstract_factory2;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
import com.bkjeon.abstract_factory2.linux.LinuxGuiFac;
public class Main {
public static void main(String[] args) {
GuiFac fac = new LinuxGuiFac();
Button button = fac.createButton();
TextArea area = fac.createTextArea();
button.click();
System.out.println(area.getText());
}
}
실행결과
리눅스 버튼
리눅스 텍스트 에어리어
그 다음 mac도 똑같이 만들어보자. 우선 mac 관련 클래스들을 생성하자.
[MacGuiFac.java]
package com.bkjeon.abstract_factory2.mac;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class MacGuiFac implements GuiFac {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextArea createTextArea() {
return new MacTextArea();
}
}
[MacButton.java]
package com.bkjeon.abstract_factory2.mac;
import com.bkjeon.abstract_factory2.abst.Button;
public class MacButton implements Button {
@Override
public void click() {
System.out.println("맥 버튼");
}
}
[MacTextArea.java]
package com.bkjeon.abstract_factory2.mac;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class MacTextArea implements TextArea {
@Override
public String getText() {
return "맥 텍스트 에어리어";
}
}
메인 클래스를 수정하자.
[Main.java]
package com.bkjeon.abstract_factory2;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
import com.bkjeon.abstract_factory2.mac.MacGuiFac;
public class Main {
public static void main(String[] args) {
// GuiFac fac = new LinuxGuiFac();
GuiFac fac = new MacGuiFac(); // 이 부분만 변경해주면 된다.
Button button = fac.createButton();
TextArea area = fac.createTextArea();
button.click();
System.out.println(area.getText());
}
}
실행결과
맥 버튼
맥 텍스트 에어리어
또 똑같은 작업이니 win 패키지도 구현해보자.
[WinGuiFac.java]
package com.bkjeon.abstract_factory2.win;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class WinGuiFac implements GuiFac {
@Override
public Button createButton() {
return new WinButton();
}
@Override
public TextArea createTextArea() {
return new WinTextArea();
}
}
[WinButton.java]
package com.bkjeon.abstract_factory2.win;
import com.bkjeon.abstract_factory2.abst.Button;
public class WinButton implements Button {
@Override
public void click() {
System.out.println("윈도우 버튼");
}
}
[WinTextArea.java]
package com.bkjeon.abstract_factory2.win;
import com.bkjeon.abstract_factory2.abst.TextArea;
public class WinTextArea implements TextArea {
@Override
public String getText() {
return "윈도우 텍스트 에어리어";
}
}
[Main.java]
package com.bkjeon.abstract_factory2;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
import com.bkjeon.abstract_factory2.win.WinGuiFac;
public class Main {
public static void main(String[] args) {
// GuiFac fac = new LinuxGuiFac();
// GuiFac fac = new MacGuiFac();
GuiFac fac = new WinGuiFac();
Button button = fac.createButton();
TextArea area = fac.createTextArea();
button.click();
System.out.println(area.getText());
}
}
실행결과
윈도우 버튼
윈도우 텍스트 에어리어
위와 같이 Mac이면 new MacGuiFac(); 를 사용하고 Linux면 new LinuxGuiFac(); 를 사용하는 것은 패턴을 잘 사용한 것이 아니라고 한다 그래서 하나 패키지를 더 만들자.
concrete 패키지를 생성
[FactoryInstance.java]
package com.bkjeon.abstract_factory2.concrete;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.linux.LinuxGuiFac;
import com.bkjeon.abstract_factory2.mac.MacGuiFac;
import com.bkjeon.abstract_factory2.win.WinGuiFac;
public class FactoryInstance {
// 시스템 OS 정보에 따라 필요한 팩토리를 리턴
public static GuiFac getGuiFac(String osName) {
switch (getOsCode(osName)) {
case 0: return new MacGuiFac();
case 1: return new LinuxGuiFac();
case 2: return new WinGuiFac();
}
return null;
}
private static int getOsCode(String osName) {
// 해당 내용은 System.getProperty("os.name") 값에 따라서 정규표현식으로 리턴값을 지정해주면 된다.
if (osName.equals("Mac OS X")) {
return 0;
} else if (osName.equals("Windows 10")) {
return 2;
}
return 1;
}
}
Main 클래스를 변경한다.
[Main.java]
package com.bkjeon.abstract_factory2;
import com.bkjeon.abstract_factory2.abst.Button;
import com.bkjeon.abstract_factory2.abst.GuiFac;
import com.bkjeon.abstract_factory2.abst.TextArea;
import com.bkjeon.abstract_factory2.concrete.FactoryInstance;
public class Main {
public static void main(String[] args) {
// GuiFac fac = new LinuxGuiFac();
// GuiFac fac = new MacGuiFac();
// GuiFac fac = new WinGuiFac();
// 만약 여기서 FactoryInstance.getGuiFac() 에다 넘겨주는것이 일정하다면
// Linux면 LinuxGuiFac를 넘겨주고, Mac에서는 MacGuiFac를 넘겨주게 한다면은 메인클래스의 코드는 건들 필요가 없어진다.
// abst와 concrete 패키지는 라이브러리 형태로 적용될거고 이 두개에서 인터페이스만 사용해서 우리가 원하는 기능을 구현하면 된다.
// 즉, 우리가 어떤 환경에서 해당 프로그램을 돌리든지 동일한 동작을 하기위해선 해당 소스가 OS와 관계없이 동일하게 적용되어야 한다.
GuiFac fac = FactoryInstance.getGuiFac(System.getProperty("os.name"));
Button button = fac.createButton();
TextArea area = fac.createTextArea();
button.click();
System.out.println(area.getText());
}
}
'Java & Kotlin > Java' 카테고리의 다른 글
[Design Pattern] Composite Pattern (0) | 2019.12.21 |
---|---|
[Design Pattern] Bridge Pattern (0) | 2019.12.12 |
[Design Pattern] Builder Pattern (0) | 2019.12.08 |
[Design Pattern] Prototype Pattern (0) | 2019.12.08 |
[Design Pattern] Singleton Pattern (0) | 2019.12.07 |