생성 패턴 - Factory

이유석·2022년 5월 31일
0

Design Pattern

목록 보기
3/10
post-thumbnail

Factory 패턴

Factory 패턴이 나오게 된 이유

객체 지향 디자인 패턴의 기본 원칙은 확장에 있어서는 열려 있어야 하며, 수정에 있어서는 닫혀 있어야 한다는 것이다. (OCP, Open Closed Principle)

여기서 수정에 있어서 닫혀 있어야 한다는 말에 주목해보자.

  • 코드를 수정하지 않아도 모듈의 기능을 확장하거나 변경할 수 있어야 한다.
    때문에, 수정이 일어날 가능성이 큰 부분과 그렇지 않는 부분을 분리하는 것이 좋다.

객체는 속성과 함수가 변경, 또는 추가 될 수 있다.

  • 이에 따라 객체의 생성을 담당하는 코드는 변경 가능성이 높다.
    객체의 생성을 담당하는 클래스를 한 곳에서 관리하여 결합도를 줄이기 위하여 팩토리 패턴이 나타나게 된 것이다.

결합도(의존성) 이란?

정의

  • 한 클래스의 변경점이 얼마나 다른 클래스에 영향을 주는가를 의미한다.

예제 코드

class Product {
	init() {}
}
class User = {
	let p = Product();
}
  • 위 코드에서 User 클래스는 Product 클래스를 사용하고 있다. 즉 의존관계이다.
  • 이때 의존의 대상이 Product 클래스가 사라지면, User 클래스는 동작할 수 없게된다.

이러한 코드를 결합도가 높은 코드라고 말할 수 있다.

종류

  • Factory Method (팩토리 메소드) 패턴 : 객체 생성을 서브클래스에서 결정
  • Abstract Factory (추상 팩토리) 패턴 : 서로 연관된 객체들의 제품군을 생성할 때 유용한 방법

Factory Method 패턴

정의

  • 어떤 객체의 인스턴스를 생성할지를 서브 클래스에서 결정하는 디자인 패턴이다.

  • 객체 생성을 처리하는 메소드를 외부에 두지 않고, 서브 클래스(팩토리)에 둠으로써 객체 생성을 위임하는 패턴

예제 코드

컴퓨터에는 다양한 부품이 존재한다. 특정 제조사 선택시 해당 제조사의 부품 객체를 만들어주는 코드를 작성해보자.

NotebookFactory 클래스는 입력받은 특정 type에 따라 LGNotebook 객체를 생성할지, SamSungNotebook 객체를 생성할지 결정한다.

public class NotebookFactory {
	public Notebook createNotebook(String type) {
    	Notebook notebook = null;
        
        switch (type) {
        	case 'LG' :
            	notebook = new LGNotebook();
                break;
            case 'SamSung':
            	notebook = new SamSungNotebook();
            	break;
        }
    }
}

여기서 주의할 점은 LGNotebook 클래스와 SamSungNotebook 클래스 모두 Notebook 클래스를 상속한다는 것입니다.

public interface Notebook {}
public class LGNotebook implements Notebook {
	public LGNotebook() {
    	System.out.println("LG 노트북");
    }
}
public class SamSungNotebook implements Notebook {
	public SamSungNotebook() {
    	System.out.println("SamSung 노트북");
    }
}

MouseFactory 클래스는 입력받은 특정 type에 따라 LGMouse 객체를 생성할지, SamSungMouse 객체를 생성할지 결정한다.

public class MouseFactory {
	public Mouse createMouse(String type) {
    	Mouse mouse = null;
        
        switch (type) {
        	case 'LG' :
            	mouse = new LGMouse();
                break;
            case 'SamSung':
            	mouse = new SamSungMouse();
            	break;
        }
    }
}

여기서 주의할 점은 LGMouse 클래스와 SamSungMouse 클래스 모두 Mouse 클래스를 상속한다는 것입니다.

public interface Mouse {}
public class LGMouse implements Mouse {
	public LGMouse() {
    	System.out.println("LG 마우스");
    }
}
public class SamSungMouse implements Mouse {
	public SamSungMouse() {
    	System.out.println("SamSung 마우스");
    }
}

마지막으로 Client인 ComputerFactory 클래스에서 어떤 제조사의 노트북과 마우스를 선택할지를 결정합니다.

public class ComputerFactory {
	public void createComputer(String type){
        NotebookFactory notebookFactory = new NotebookFactory();
        MouseFactory mouseFactory = new MouseFactory();

        notebookFactory.createNotebook(type);
        mouseFactory.createMouse(type);
        System.out.println("--- " + type + " 컴퓨터 완성 ---");
    }
}

테스트

public class FactoryMethodPatternMain {

	public static void main(String[] args) {
		ComputerFactory computerFactory = new ComputerFactory();
		computerFactory.createComputer("LG");
	}

}

/* 출력
LG 노트북
LG 마우스
--- LG 컴퓨터 완성 ---
*/

장/단점

장점

  • 객체간의 결합도를 낮출 수 있다.
  • 단일 책임 원칙을 따른다.
  • 프로그램의 코드에서 생성자 코드를 분리함으로써 코드를 더욱 간결하게 만들 수 있다.
  • 개방 폐쇄 원칙을 따른다. 기존 client의 코드를 파괴하지 않고 새로운 타입(컴퓨터 부품)을 추가할 수 있다.

단점

  • 패턴을 구현할 많은 서브 클래스를 도입함으로써 코드가 복잡해질 수 있다.

Abstract Factory 패턴

정의

  • 많은 수의 연관된 서브 클래스를 특정 그룹으로 묶어 한번에 교체할 수 있도록 만든 디자인 패턴이다.

  • 팩토리 메소드 패턴과 유사하지만, 한가지 다른 것은 팩토리를 만드는 상위 팩토리(super-factory) 클래스가 존재한다.

예제 코드

컴퓨터에는 다양한 부품이 존재한다. 특정 제조사 선택시 해당 제조사의 부품 객체를 만들어주는 코드를 작성해보자.
팩토리 메소드 패턴과 다른점은 각 제조사 별로 ComputerFactory가 존재하고 해다 Factory에서 Notebook과 Mouse를 제조한다.

public interface ComputerFactory {
	public Notebook createNotebook();
    public Mouse createMouse();
}

LGComputerFactory

public class LGComputerFactory implements ComputerFactory {
	@Override
	public LGNotebook createNotebook() {
		return new LGNotebook();
	}

	@Override
	public LGMouse createMouse() {
		return new LGMouse();
	}
}

SamSungComputerFactory

	@Override
	public SamSungNotebook createNotebook() {
		return new SamSungNotebook();
	}

	@Override
	public SamSungMouse createMouse() {
		return new SamSungMouse();
	}

Factory

public class Factory {
	public void createComputer(String type){
        NewComputerFactory newcomputerFactory= null;
        switch (type){
            case "LG":
            	newcomputerFactory = new LGComputerFactory();
                break;

            case "SamSung":
            	newcomputerFactory = new SamSungComputerFactory();
                break;
        }

        newcomputerFactory.createNotebook();
        newcomputerFactory.createMouse();
    }
}

테스트

public class AbstractFactoryPatternMain {

	public static void main(String[] args) {
		Factory computerFactory = new Factory();
		computerFactory.createComputer("LG");
	}

}

/* 출력
LG 노트북
LG 마우스
*/

장/단점

장점

  • Factory로 부터 만들어진 각 객체들이 서로 호환될 수 있음을 보장한다.
  • 객체간의 결합도를 낮출 수 있다.
  • 단일 책임 원칙을 따른다.
  • 프로그램의 코드에서 생성자 코드를 분리함으로써 코드를 더욱 간결하게 만들 수 있다.
  • 개방 폐쇄 원칙을 따른다. 기존 client의 코드를 파괴하지 않고 새로운 타입을 추가 할 수 있다.

단점

  • 패턴을 구현할 많은 서브 클래스를 도입합으로써 코드가 복잡 해 질 수 있다.
profile
https://github.com/yuseogi0218

0개의 댓글