답변:
나는 수업이 '사람'이라는 관점에서 디자인 패턴에 대해 생각하는 것을 좋아하며 패턴은 사람들이 서로 이야기하는 방식입니다.
나에게 공장 패턴은 고용 기관과 같습니다. 다양한 수의 근로자가 필요한 사람이 있습니다. 이 사람은 그들이 고용 한 사람들에게 필요한 정보를 알고 있을지 모르지만 그게 전부입니다.
따라서 신입 사원이 필요할 때 고용 기관에 연락하여 필요한 것을 알려줍니다. 이제 실제로 누군가를 고용 하려면 혜택, 적격성 검증 등 많은 것을 알아야합니다. 그러나 고용하는 사람은이를 알 필요가 없습니다. 고용 기관이 모든 것을 처리합니다.
같은 방식으로 팩토리를 사용하면 소비자는 자신이 생성 된 방법이나 종속성이 무엇인지에 대한 세부 정보를 알 필요없이 새로운 객체를 만들 수 있습니다. 실제로 원하는 정보 만 제공하면됩니다.
public interface IThingFactory
{
Thing GetThing(string theString);
}
public class ThingFactory : IThingFactory
{
public Thing GetThing(string theString)
{
return new Thing(theString, firstDependency, secondDependency);
}
}
따라서 ThingFactory의 소비자는 소비자로부터 오는 문자열 데이터를 제외하고 Thing의 종속성에 대해 알 필요없이 Thing을 얻을 수 있습니다.
within an object instead of a Factory class
. 나는 그가 ctor를 private로 만들고 정적 메소드를 사용하여 클래스를 인스턴스화 (객체 생성)하는 시나리오를 의미한다고 생각합니다. 그러나이 예제를 따르 ThingFactory
려면 먼저 클래스 를 인스턴스화하여 Thing
객체를 가져와야 Factory class
합니다.
팩토리 메소드는 생성자에 대한 대안으로 고려해야합니다. 주로 생성자가 표현력이 충분하지 않은 경우입니다.
class Foo{
public Foo(bool withBar);
}
다음과 같이 표현 적이 지 않습니다.
class Foo{
public static Foo withBar();
public static Foo withoutBar();
}
팩토리 클래스는 객체를 생성하기 위해 복잡한 프로세스가 필요할 때, 구성에 실제 클래스에 대해 원하지 않는 종속성이 필요할 때, 다른 객체를 생성해야 할 때 유용합니다.
개인적으로 이해하기 위해 별도의 Factory 클래스를 찾는 한 가지 상황은 만들려는 최종 객체가 다른 여러 객체에 의존하는 경우입니다. 예를 들면, PHP에서 : 당신이 있다고 가정 House
차례로이 객체 Kitchen
와 LivingRoom
객체 및 LivingRoom
객체는이 TV
객체의 내부뿐만 아니라.
이를 달성하는 가장 간단한 방법은 각 객체가 구성 메소드에서 하위를 House
작성하는 것입니다. 그러나 특성이 상대적으로 중첩 된 경우 작성에 실패하면 실패한 항목을 정확하게 분리하는 데 약간의 시간이 소요됩니다.
대안은 다음을 수행하는 것입니다 (멋진 용어가 마음에 들면 의존성 주입).
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
여기서 House
실패 를 만드는 과정은 볼 곳이 하나 뿐이지 만 새로운 것을 원할 때 마다이 청크를 사용해야하는 것은 House
편리하지 않습니다. 공장을 입력하십시오 :
class HouseFactory {
public function create() {
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
return $HouseObj;
}
}
$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();
여기 팩토리 덕분에 a 생성 프로세스 House
가 추상화되어 (만 생성하려고 할 때 모든 단일 종속성을 생성하고 설정할 필요가 없음 House
) 동시에 중앙 집중화되어 유지 관리가 더 쉽습니다. 별도의 팩토리를 사용하는 것이 유리한 이유 (예 : 테스트 가능성)가 있지만 Factory 클래스가 유용한 방법을 가장 잘 설명하기 위해이 특정 사용 사례를 찾습니다.
HouseFactory
클래스에 정확히 어떻게 전달 됩니까?
create
메소드에 전달할 필요는 없습니다 . 예를 들어, House
항상 같은 종류를 가지 LivingRoom
려면 인자로 전달되는 것이 아니라 팩토리 클래스에서 매개 변수를 하드 코딩하는 것이 합리적 일 수 있습니다. 또는 몇 종류 가 있고 각 유형에 대해 하드 코딩 된 매개 변수가있는 스위치 가있는 경우 메소드에 type
인수 를 제공 할 수 있습니다 . HouseFactory::create
LivingRoom
팩토리 또는 팩토리 방법을 사용하여 아이디어를 명확하게 구별하는 것이 중요합니다. 둘 다 상호 배타적 인 다른 종류의 객체 생성 문제를 해결하기위한 것입니다.
"공장 방법"에 대해 구체적으로 설명하겠습니다.
첫 번째는 추가 응용 프로그램 개발에 사용될 라이브러리 또는 API를 개발할 때 팩토리 방법이 작성 패턴에 가장 적합한 선택 중 하나라는 것입니다. 뒤에 이유; 필요한 기능을 가진 객체를 언제 만들지 만 객체 유형이 결정되지 않은 상태이거나 동적 매개 변수가 전달되는 것으로 결정됩니다 .
요점은 팩토리 패턴 자체를 사용하여 거의 동일하게 달성 할 수 있지만 팩토리 패턴이 강조 표시된 문제에 사용될 경우 하나의 큰 단점이 시스템에 도입 될 것입니다. 이는 다른 객체 (하위 클래스 객체)를 만드는 논리가 미래에는 다른 플랫폼을 위해 라이브러리의 기능을 확장해야 할 때 일부 비즈니스 조건에 특정해야합니다 (보다 기술적으로는 기본 인터페이스 또는 추상 클래스의 하위 클래스를 더 추가해야 팩토리가 기존 객체 외에도 해당 객체를 반환합니다) 일부 동적 매개 변수를 기반으로) 비용이 많이 들며 디자인 관점에서 좋지 않은 팩토리 클래스의 논리를 변경 (확장) 할 때마다. 다른 한편으로, "공장 방법"
interface Deliverable
{
/*********/
}
abstract class DefaultProducer
{
public void taskToBeDone()
{
Deliverable deliverable = factoryMethodPattern();
}
protected abstract Deliverable factoryMethodPattern();
}
class SpecificDeliverable implements Deliverable
{
/***SPECIFIC TASK CAN BE WRITTEN HERE***/
}
class SpecificProducer extends DefaultProducer
{
protected Deliverable factoryMethodPattern()
{
return new SpecificDeliverable();
}
}
public class MasterApplicationProgram
{
public static void main(String arg[])
{
DefaultProducer defaultProducer = new SpecificProducer();
defaultProducer.taskToBeDone();
}
}
다음과 같은 경우 객체 내부에서 팩토리 메소드 를 사용하는 것이 좋습니다 .
다음과 같은 경우 추상 팩토리 클래스 를 사용하는 것이 좋습니다 .
에서 UML
제품 : 팩토리 메소드가 작성하는 오브젝트의 인터페이스를 정의합니다.
ConcreteProduct : 제품 인터페이스 구현
제작자 : Factory 메서드 선언
ConcreateCreator : Factory 메서드를 구현하여 ConcreteProduct의 인스턴스를 반환
문제 설명 : 게임 인터페이스를 정의하는 팩토리 메소드를 사용하여 게임 팩토리를 작성하십시오.
코드 스 니펫 :
import java.util.HashMap;
/* Product interface as per UML diagram */
interface Game{
/* createGame is a complex method, which executes a sequence of game steps */
public void createGame();
}
/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
public Chess(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Chess game");
System.out.println("Opponents:2");
System.out.println("Define 64 blocks");
System.out.println("Place 16 pieces for White opponent");
System.out.println("Place 16 pieces for Black opponent");
System.out.println("Start Chess game");
System.out.println("---------------------------------------");
}
}
class Checkers implements Game{
public Checkers(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Checkers game");
System.out.println("Opponents:2 or 3 or 4 or 6");
System.out.println("For each opponent, place 10 coins");
System.out.println("Start Checkers game");
System.out.println("---------------------------------------");
}
}
class Ludo implements Game{
public Ludo(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Ludo game");
System.out.println("Opponents:2 or 3 or 4");
System.out.println("For each opponent, place 4 coins");
System.out.println("Create two dices with numbers from 1-6");
System.out.println("Start Ludo game");
System.out.println("---------------------------------------");
}
}
/* Creator interface as per UML diagram */
interface IGameFactory {
public Game getGame(String gameName);
}
/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {
HashMap<String,Game> games = new HashMap<String,Game>();
/*
Since Game Creation is complex process, we don't want to create game using new operator every time.
Instead we create Game only once and store it in Factory. When client request a specific game,
Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
*/
public GameFactory(){
games.put(Chess.class.getName(),new Chess());
games.put(Checkers.class.getName(),new Checkers());
games.put(Ludo.class.getName(),new Ludo());
}
public Game getGame(String gameName){
return games.get(gameName);
}
}
public class NonStaticFactoryDemo{
public static void main(String args[]){
if ( args.length < 1){
System.out.println("Usage: java FactoryDemo gameName");
return;
}
GameFactory factory = new GameFactory();
Game game = factory.getGame(args[0]);
if ( game != null ){
game.createGame();
System.out.println("Game="+game.getClass().getName());
}else{
System.out.println(args[0]+ " Game does not exists in factory");
}
}
}
산출:
java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess
이 예제는 Factory
을 구현하여 클래스 를 보여줍니다 FactoryMethod
.
Game
모든 유형의 게임을위한 인터페이스입니다. 복잡한 방법을 정의합니다.createGame()
Chess, Ludo, Checkers
게임의 다양한 변형으로 createGame()
public Game getGame(String gameName)
이다 FactoryMethod
의 IGameFactory
클래스
GameFactory
생성자에서 다른 유형의 게임을 미리 만듭니다. IGameFactory
팩토리 메소드를 구현 합니다.
게임 이름은 명령 행 인수로 전달됩니다 NotStaticFactoryDemo
getGame
in GameFactory
은 게임 이름 을 받아들이고 해당 Game
객체를 반환 합니다.
공장:
인스턴스화 논리를 클라이언트에 노출시키지 않고 객체를 만듭니다.
공장 방법
객체를 생성하기위한 인터페이스를 정의하되 서브 클래스가 인스턴스화 할 클래스를 결정하도록합니다. Factory 메소드는 클래스가 서브 클래스에 대한 인스턴스화를 연기하게합니다
사용 사례 :
사용시기 : Client
런타임에 어떤 구체적인 클래스를 작성해야하는지 모르지만 작업을 수행 할 클래스를 얻으려고합니다.
getArea()
공장 방법이 아닙니다 전혀 .
팩토리 클래스는 리턴하는 오브젝트 유형에 개인 생성자가있는 경우, 다른 팩토리 클래스가 리턴하는 오브젝트에 다른 특성을 설정하거나 특정 팩토리 유형이 리턴 콘크리트 유형과 결합 된 경우에 유용합니다.
WCF 는 ServiceHostFactory 클래스를 사용하여 서로 다른 상황에서 ServiceHost 개체를 검색합니다. 표준 ServiceHostFactory는 IIS에서 .svc 파일의 ServiceHost 인스턴스를 검색 하는 데 사용되지만 WebScriptServiceHostFactory는 JavaScript 클라이언트에 직렬화를 반환하는 서비스에 사용됩니다. ADO.NET Data Services에는 고유 한 특수 DataServiceHostFactory가 있으며 ASP.NET에는 서비스에 개인 생성자가 있으므로 ApplicationServicesHostFactory가 있습니다.
팩토리를 소비하는 클래스가 하나 뿐인 경우 해당 클래스 내에서 팩토리 메소드를 사용할 수 있습니다.
주문 및 고객 클래스를 설계해야하는 시나리오를 고려하십시오. 단순성과 초기 요구 사항을 위해 Order 클래스에 대한 팩토리가 필요하지 않으며 많은 'new Order ()'문으로 응용 프로그램을 채우십시오. 상황이 잘 작동합니다.
이제 고객 연관 (새로운 종속성)없이 주문 오브젝트를 인스턴스화 할 수 없다는 새로운 요구 사항이 제시되었습니다. 이제 다음 사항을 고려해야합니다.
1- 새로운 구현에만 작동하는 생성자 과부하를 만듭니다. (허용하지 않는다). 2- Order () 서명을 변경하고 호출 할 때마다 변경합니다. (좋은 습관과 진정한 고통이 아닙니다).
대신 주문 클래스에 대한 팩토리를 생성 한 경우 한 줄의 코드 만 변경하면됩니다. 거의 모든 집계 연관에 대해 팩토리 클래스를 제안합니다. 희망이 도움이됩니다.
사용 측면에서 다른 객체를 생성하려는 경우 쓸모있다.
public class factoryMethodPattern {
static String planName = "COMMERCIALPLAN";
static int units = 3;
public static void main(String args[]) {
GetPlanFactory planFactory = new GetPlanFactory();
Plan p = planFactory.getPlan(planName);
System.out.print("Bill amount for " + planName + " of " + units
+ " units is: ");
p.getRate();
p.calculateBill(units);
}
}
abstract class Plan {
protected double rate;
abstract void getRate();
public void calculateBill(int units) {
System.out.println(units * rate);
}
}
class DomesticPlan extends Plan {
// @override
public void getRate() {
rate = 3.50;
}
}
class CommercialPlan extends Plan {
// @override
public void getRate() {
rate = 7.50;
}
}
class InstitutionalPlan extends Plan {
// @override
public void getRate() {
rate = 5.50;
}
}
class GetPlanFactory {
// use getPlan method to get object of type Plan
public Plan getPlan(String planType) {
if (planType == null) {
return null;
}
if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
return new DomesticPlan();
} else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
return new CommercialPlan();
} else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
return new InstitutionalPlan();
}
return null;
}
}
작업해야하는 객체에 대해 객체 생성을 하위 클래스로 연기하는 모든 클래스를 팩토리 패턴의 예로 볼 수 있습니다.
https://stackoverflow.com/a/49110001/504133 의 또 다른 답변에서 자세히 언급했습니다.
나는 그것이 당신의 코드로 가져 오려는 느슨한 결합 정도에 달려 있다고 생각합니다.
팩토리 메소드는 사물을 잘 분리하지만 팩토리 클래스 번호는 아닙니다.
다시 말해, 팩토리 클래스를 사용하는 단순한 팩토리를 사용하는 것보다 팩토리 메소드를 사용하는 경우 변경하는 것이 더 쉽습니다.
https://connected2know.com/programming/java-factory-pattern/ 예제를 살펴보십시오 . 이제 새로운 동물을 가져오고 싶다고 상상해보십시오. 팩토리 클래스에서는 팩토리를 변경해야하지만 팩토리 메소드에서는 새 서브 클래스 만 추가하면됩니다.
나는 공장을 도서관의 개념에 비유한다. 예를 들어 숫자로 작업하기위한 라이브러리와 모양으로 작업하기위한 라이브러리를 가질 수 있습니다. 이러한 라이브러리의 기능을 논리적으로 명명 된 디렉토리에 Numbers
또는 로 저장할 수 있습니다 Shapes
. 이것들은 정수, 플로트, 더불, 길거나 직사각형, 원, 삼각형, 오각형을 포함 할 수있는 일반적인 유형입니다.
팩토리 페터는 다형성, 의존성 주입 및 제어 반전을 사용합니다.
팩토리 패턴의 명시된 목적은 다음과 같습니다. Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
운영 체제 또는 프레임 워크를 구축하고 모든 개별 구성 요소를 구축한다고 가정 해 봅시다.
다음은 PHP의 팩토리 패턴 개념에 대한 간단한 예입니다. 나는 100 %가 아닐 수도 있지만 간단한 예를 제공하기위한 것입니다. 나는 전문가가 아닙니다.
class NumbersFactory {
public static function makeNumber( $type, $number ) {
$numObject = null;
$number = null;
switch( $type ) {
case 'float':
$numObject = new Float( $number );
break;
case 'integer':
$numObject = new Integer( $number );
break;
case 'short':
$numObject = new Short( $number );
break;
case 'double':
$numObject = new Double( $number );
break;
case 'long':
$numObject = new Long( $number );
break;
default:
$numObject = new Integer( $number );
break;
}
return $numObject;
}
}
/* Numbers interface */
abstract class Number {
protected $number;
public function __construct( $number ) {
$this->number = $number;
}
abstract public function add();
abstract public function subtract();
abstract public function multiply();
abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Integer Implementation */
class Integer extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Short Implementation */
class Short extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Double Implementation */
class Double extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Long Implementation */
class Long extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
$number = NumbersFactory::makeNumber( 'float', 12.5 );
NumbersFactory::makeNumber( 'float', 12.5 );
말해주는 것 입니까? 이것이 내가 공장에 대해 이해하지 못하는 것입니다 ... 요점은 무엇입니까? new Float(12.5);
Float