티스토리 뷰
728x90
반응형
소스코드 로직 상에서 객체를 생성할 일이 많습니다. 객체가 필요할 때마다, new 키워드로 객체를 생성하고 가비지 컬렉터가 알아서 처리하도록 두는 게 좋을까요? 사실 그다지 좋은 방법이 아닐 것입니다. 프로그램 실행 중 객체는 단 하나만 있어도 되는 경우가 있을 것이고, 특정 객체로부터 복제하여 사용하는 것이 좋을 수 도 있습니다. 뿐만 아니라, 공장처럼 객체를 생성하는 전용 클래스를 만들어서 객체 생성 코드를 관리하는 방법도 있습니다.
이번 포스팅에서는 디자인 패턴 중 생성 패턴 중 싱글턴, 프로토타입, 팩토리 메서드, 빌더, 추상 팩토리 패턴에 대해 알아보겠습니다.
디자인 패턴 정의
- 프로그래머가 애플리케이션이나 시스템을 디자인할 때, 공통된 문제들을 해결하는데 쓰이는 형식화된 가장 좋은 관행
- Programming Language 별로 디자인 패턴을 구현하는 소스코드 구조가 다를 수 있음
생성 패턴 (Creational Pattern)
인스턴스를 만드는 절차를 추상화하는 패턴
싱글턴 (Singleton)
- 프로그램 내에서 오직 하나의 인스턴스가 생성됨을 보장하는 패턴
- 프로그램 어디에서든 인스턴스를 접근할 수 있음
public class Singleton {
private static Singleton singleton = null;
// 외부에서 직접 생성하지 못하도록 private 선언
private Singleton() {
}
// 오직 1개의 객체만 생성
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
@Test
public void TestSingleton()
{
for( int i = 0; i < 5; i++ ){
System.out.println(Singleton.getInstance().toString());
}
}
<Console>
SingleObj@98c449
SingleObj@98c449
SingleObj@98c449
SingleObj@98c449
SingleObj@98c449
프로토타입 (Prototype)
- 이미 존재하는 객체를 이용하여, 새로운 객체를 생성하는 패턴
- 객체 생성 시간이 많이 소요될 때 주로 사용 (외부 시스템으로부터 데이터를 수신하여 객체를 생성하는 경우)
- 주로 java의 clone 메서드를 통해 구현
import java.util.ArrayList;
import java.util.List;
/* Prototype */
public class Prototype implements Cloneable {
private List<String> datalist;
public Prototype() {
datalist = new ArrayList<String>();
}
public Prototype(List<String> data) {
this.datalist = data;
}
public List<String> getDataList() {
return this.datalist;
}
public boolean loadData() {
boolean res = true;
// data loading하는 경우는 DB 또는 Http통신 등 다양한 방법으로 이루어 질 수 있음
res &= datalist.add("data1");
res &= datalist.add("data2");
res &= datalist.add("data3");
res &= datalist.add("data4");
return res;
}
@Override
protected Object clone() throws CloneNotSupportedException {
List<String> tmp = new ArrayList<String>(); // 깊은 복사를 통해 객체 내부 데이터를 복제함
for (String data : datalist) {
tmp.add(data);
}
return new Prototype(tmp);
}
}
@Test
public void TestProtoType() throws CloneNotSupportedException {
Prototype proto = new Prototype();
proto.loadData();
Prototype cloneProto = (Prototype)proto.clone();
cloneProto.getDataList().remove(0);
System.out.println("Address : "+proto+"\tOriginal Object : "+proto.getDataList());
System.out.println("Address : "+cloneProto+"\tClone Object : "+cloneProto.getDataList());
}
<Console>
Address : cleancode.designpattern.Prototype@3b7951 Original Object : [data1, data2, data3, data4]
Address : cleancode.designpattern.Prototype@514713 Clone Object : [data2, data3, data4]
팩토리 메서드 (Factory Methods)
- 객체 생성을 서브클래스에게 위임하는 디자인 패턴
- 클래스 생성과 비즈니스 처리 로직을 분리하여 결합도를 낮추기 위해 사용
/* Creator */
public abstract class Factory {
public Shape getShape(ShapeType type) {
return this.create(type);
}
protected abstract Shape create(ShapeType type);
}
/* Creator1 */
public class FactoryShape extends Factory {
@Override
public Shape create(ShapeType type) {
switch (type) {
case Triangle:
return new ShapeTriangle();
case Rectangle:
return new ShapeRectangle();
default:
throw new RuntimeException(type.toString() + "is not existed");
}
}
}
/* Product */
public abstract class Shape {
abstract public String draw();
}
/* Product1 */
public class ShapeRectangle extends Shape{
@Override
public String draw() {
return "Rectangle";
}
}
public class ShapeTriangle extends Shape {
@Override
public String draw() {
return "Triangle";
}
}
public enum ShapeType {
Triangle, Rectangle
}
@Test
public void TestFactoryMethod(){
Factory factory = new FactoryShape();
Shape shapeObj = factory.getShape(ShapeType.Rectangle);
Shape shapeObj2 = factory.getShape(ShapeType.Triangle);
System.out.println(shapeObj.draw());
System.out.println(shapeObj2.draw());
}
<Console>
Rectangle
Triangle
빌더 (Builder)
- 다양한 상태의 객체 생성이 필요할 때 사용하는 객체 생성 패턴
- 객체 생성과 표현부를 분리할 수 있음
/* Product */
public class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
public void setDough(String dough) {
this.dough = dough;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
public void setTopping(String topping) {
this.topping = topping;
}
public String getDough() {
return this.dough;
}
public String getSauce() {
return this.sauce;
}
public String getTopping() {
return this.topping;
}
}
/* Builder */
public abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza(){
return pizza;
}
public void createNewPizzaProduct(){
pizza = new Pizza();
}
public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}
/* ConcreteBuilder */
public class HawaiianPizzaBuilder extends PizzaBuilder {
@Override
public void buildDough() {
pizza.setDough("cross");
}
@Override
public void buildSauce() {
pizza.setSauce("mild");
}
@Override
public void buildTopping() {
pizza.setTopping("ham,pineApple");
}
}
public class SpicyPizzaBuilder extends PizzaBuilder {
@Override
public void buildDough() {
pizza.setDough("pan baked");
}
@Override
public void buildSauce() {
pizza.setSauce("hot");
}
@Override
public void buildTopping() {
pizza.setTopping("pepperoni,salami");
}
}
/* Director */
public class Cook {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pizzaBuilder) {
this.pizzaBuilder = pizzaBuilder;
}
public Pizza getPizza() {
return pizzaBuilder.pizza;
}
public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}
@Test
public void TestBuilder() {
Cook cook = new Cook();
PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
cook.setPizzaBuilder(hawaiianPizzaBuilder);
cook.constructPizza();
Pizza pizza = cook.getPizza();
System.out.println(pizza.toString() + "," + pizza.getDough() + "," + pizza.getSauce() + "," + pizza.getTopping());
cook.setPizzaBuilder(spicyPizzaBuilder);
cook.constructPizza();
pizza = cook.getPizza();
System.out.println(pizza.toString() + "," + pizza.getDough() + ","+ pizza.getSauce() + "," + pizza.getTopping());
}
Console
cleancode.designpattern.builder.Pizza@1663380,cross,mild,ham,pineApple
cleancode.designpattern.builder.Pizza@137e0d2,pan baked,hot,pepperoni,salami
추상 팩토리 (Abstract Factory)
- 서로 관련된 객체들을 동시에 생성할 때 이를 추상화된 인터페이스로 객체 생성 방식을 제공하는 패턴
- 팩토리 메서드로 객체를 생성할 경우, 클래스 간 결합도가 증가하는 문제가 발생하여 이를 해결하고자 사용
/* AbstractFactory */
public abstract class GUIFactory {
public abstract Button createButton();
public abstract Scroll createScroll();
}
/* Factory1 */
public class GUILinuxFactory extends GUIFactory {
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public Scroll createScroll() {
return new VerticalScroll();
}
}
/* Factory2 */
public class GUIWinFactory extends GUIFactory {
@Override
public Button createButton() {
return new WinButton();
}
@Override
public Scroll createScroll() {
return new HorizontalScroll();
}
}
/* Product1 */
public abstract class Button {
public abstract void paint();
}
public class LinuxButton extends Button{
@Override
public void paint() {
System.out.println("Draw Linux Button");
}
}
public class WinButton extends Button{
@Override
public void paint() {
System.out.println("Draw Win Button");
}
}
/* Product2 */
public abstract class Scroll {
public abstract void paint();
}
public class VerticalScroll extends Scroll{
@Override
public void paint() {
System.out.println("VerticalScroll");
}
}
public class WinButton extends Button{
@Override
public void paint() {
System.out.println("Draw Win Button");
}
}
@Test
public void TestAbstractFactory() throws Exception
{
GUIFactory factory = new GUIWinFactory();
Button button = factory.createButton();
Scroll scroll = factory.createScroll();
button.paint();
scroll.paint();
factory = new GUILinuxFactory();
button = factory.createButton();
scroll = factory.createScroll();
button.paint();
scroll.paint();
}
<Console>
Draw Win Button
Draw HorizontalScroll
Draw Linux Button
Draw VerticalScroll
728x90
반응형
'IT 기술' 카테고리의 다른 글
[Python] 자료형, 문자열, 숫자, 변수 사용 문법 정리 (0) | 2022.07.23 |
---|---|
디자인 패턴 - 행동 패턴 (0) | 2022.07.22 |
디자인 패턴 - 구조 패턴 (0) | 2022.07.20 |
클린코드 작성원칙(Naming, Style,주석, DeadCode,Method, SOLID) (0) | 2022.07.19 |
멀티 프로세서와 멀티 코어의 차이점 (0) | 2022.07.18 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 스프링부트 restapi
- selenium
- 코드스멜 유형
- 디자인패턴 구조패턴
- 디자인패턴
- AWS
- 스프링부트실행
- SPA
- codesmell 유형
- OSI 7계층
- oracle 메모리
- notion 업무일정관리
- TCP/UDP
- MPA
- 클린코드작성원칙
- springboot build
- notion
- 클린코드작성법
- iframe 태그 찾기
- springboot 실행
- 스프링부트빌드
- oracle pga sga
- springboot restapi
- token
- springboot rest api 서버
- 테스팅 자동화
- 멀티코어 멀티프로세서
- API Gateway 캐싱
- C++
- python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
글 보관함