답변:
Abstract Factory는 DI ( Dependency Injection )를 위한 매우 중심적인 디자인 패턴입니다 . 다음은 Abstract Factory의 적용이 솔루션 으로 받아 들여진 스택 오버플로 질문 목록입니다 .
제가 이해하는 한, 이러한 질문은 사람들이 가지고있는 실제 우려 사항이나 문제를 나타내므로 실제 사례로 시작해야합니다.
Abstract Factory 패턴 사용에 대한 실제 사례는 두 가지 다른 데이터 소스에 대한 데이터 액세스를 제공하는 것입니다. 애플리케이션이 다른 데이터 저장소를 지원한다고 가정합니다. (예 : SQL 데이터베이스 및 XML 파일). 당신은 두 개의 서로 다른 데이터 액세스 인터페이스가를 예 가지고 IReadableStore
와 IWritableStore
관계없이 사용되는 데이터 소스 유형의 응용 프로그램에서 예상되는 일반적인 방법을 정의.
어떤 유형의 데이터 소스를 사용하더라도 클라이언트 코드가 데이터 액세스 클래스를 검색하는 방식을 변경해서는 안됩니다. 귀하는 AbstractDataAccessFactory
데이터 소스의 종류가 구성된 알고 및 제공 콘크리트 공장을 클라이언트 코드, 즉 SqlDataAccessFactory
나 XmlDataAccessFactory
. 이러한 콘크리트 팩토리는 구체적인 구현을 만들 수 있습니다 (예 : SqlReadableStore
및 SqlWriteableStore
.
.NET Framework 의 DbProviderFactory 가이 패턴의 예입니다.
내가 당신을 옳게 이해한다면-질문은 왜 우리가 Factory 메서드와 추상 팩토리 패턴을 모두 가지고 있는가입니다. 다른 다형성 클래스가 다른 인스턴스화 절차를 가질 때 추상 팩토리가 필요합니다. 그리고 어떤 모듈이 객체 초기화의 세부 사항을 알지 못해도 인스턴스를 만들고 사용하기를 원합니다. 예를 들어, 일부 계산을 수행하는 Java 객체를 생성하려고합니다. 그러나 그들 중 일부는 응용 프로그램의 일부이며 다른 바이트 코드는 DB에서 읽어야합니다. 다른 한편, 왜 우리는 공장 방법이 필요한가? 그 추상적 인 공장이 그것과 겹치는 것에 동의하십시오. 그러나 어떤 경우에는 작성하는 코드가 훨씬 적고 클래스와 인터페이스가 적 으면 시스템을 더 쉽게 이해할 수 있습니다.
구체적인 클래스 자체의 객체를 생성하여 작업을 수행 할 수 있으므로 Abstract Factory Pattern의 용도는 무엇입니까? Concrete 클래스의 객체를 생성하는 팩토리 메소드가있는 이유는 무엇입니까?
Abstract Factory가 없는 경우 Client는 구체적인 클래스의 세부 사항을 알아야합니다. 이 긴밀한 결합은 Abstract Factory 에서 제거되었습니다 .
이제 Factory Method 는 클라이언트가 사용해야하는 계약을 노출합니다. Factory Method에 의해 노출 된 인터페이스를 구현하는 신제품을 추가하여 공장에 더 많은 제품을 추가 할 수 있습니다.
더 나은 이해를 위해 다음과 같은 관련 SE 질문을 참조하십시오.
팩토리 패턴과 추상 팩토리 패턴의 기본적인 차이점은 무엇입니까?
의지:
구체적인 클래스를 지정하지 않고 관련되거나 종속 된 개체의 패밀리를 만들기위한 인터페이스를 제공합니다.
당신은 이해할 수있다 이 소스 작성 기사에서 Abstract Factory 패턴의 의도, 구조, 체크리스트 및 경험 규칙을.
체크리스트 :
Abstract Factory는 코드 기반을 통합하면서 여러 플랫폼을 지원하는 데 적합합니다. Windows, Linux 및 OSX에서 실행하려는 대형 Qt 또는 GTK + 또는 .NET / Mono 프로그램이 있다고 가정합니다. 그러나 각 플랫폼에서 다른 방식으로 구현되는 기능이 있습니다 (아마도 kernel32 API 또는 POSIX 기능을 통해).
public abstract class Feature
{
public abstract int PlatformSpecificValue { get; }
public static Feature PlatformFeature
{
get
{
string platform;
// do platform detection here
if (platform == "Win32")
return new Win32Feature();
if (platform == "POSIX")
return new POSIXFeature();
}
}
// platform overrides omitted
}
이 Abstract Factory를 사용하면 UI가 현재 플랫폼에 대해 알 필요가 없습니다.
Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
추상화와 함께 작동하는 코드가 있다는 것을 쉽게 이미징 할 수 있으므로 구체적인 클래스가 아닌 추상화를 만들어야합니다.
코드를 더 잘 수정할 수 있으므로 항상 추상화에 대해 작업해야합니다.
이것은 좋은 예입니다 : http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23
Abstract Factory 패턴이 과대 평가되었습니다.
우선,이 발생하지 않는 것을 당신의 설정했는지 종종 상호 인스턴스화하려는 유형.
둘째, 인터페이스가 제공하는 간접 (추상화) 수준 일반적으로 종속성 주입으로 작업 할 때 충분합니다.
WindowsButton, MacButton, WindowsScrollBar, MacScrollbar 등이있는 WindowsGui 대 MacGui 대 ...의 전형적인 예는 방문자 및 / 또는 인터프리터 패턴을 사용하여 구체적인 버튼, 스크롤바 등을 정의하여 구현하기가 더 쉽습니다 . 실제 행동.
인스턴스화가 매우 복잡하고 단일 팩토리로는 너무 복잡하고 추하고 UI가 이해하기에는 너무 복잡한 곳에서 단순한 팩토리 패턴보다는 추상 팩토리 패턴이있는 곳이 있다고 생각합니다.
이것이 단일 클래스가 아닌 TYPE_A 브랜드라고 가정 해 봅시다. 100 가지 종류의 유사한 Type-A 클래스가 있고 그로부터 하나의 객체를 인스턴스화해야한다고 가정 해 보겠습니다. 많은 유사한 유형의 객체 브랜드에서 올바른 객체를 만들기 위해 필요한 세부적인 정교한 정보가 있다고 상상해보십시오.이 객체 엔티티에서는 어떤 매개 변수를 조정하고 어떻게 조정해야하는지 정확히 알아야합니다.
이 브랜드를위한 특별한 팩토리에서 우리는 그것들을 차별화하고 인스턴스화 할 정확한 객체와 그것을 인스턴스화하는 방법을 얻을 것입니다. 우리는 인터넷 (온라인 상점에서 어떤 색상을 사용할 수 있는지 가정 해 보겠습니다)의 입력과 백그라운드에서 실행중인 다른 애플리케이션 및 서비스 (UI가 인식하지 못하는 매개 변수)를 통해 알 수 있습니다.
그리고 아마도 내일 우리는 인스턴스화하기 위해 type_B와 type_C의 또 다른 패밀리를 가질 것입니다. 따라서 UI는 사용자가 "type_A", "type_B"또는 "type_C"를 원하는지 여부를 알 수있는 "if else"를 갖습니다. 그러나 팩토리 클래스는 빌드 할 유형 (패밀리에서)의 클래스를 정확하게 결정합니다. 조정 방법 – 매개 변수에 설정하거나 계약자에게 보낼 값. 이 모든 것-UI가 인식하지 못하는 많은 매개 변수에 따라. 이 모든 것은 단일 공장 수업에 너무 많은 것입니다.
실제 예제는 DbConnection, DbCommand 및 DbDataAdapter를 포함하는 추상 기본 클래스가 있고 System.Data.SqlClient 및 System.Data.OracleClient와 같은 .NET Framework 데이터 공급자가 공유하는 System.Data.Common 네임 스페이스에서 제공됩니다. 개발자가 특정 데이터 공급자에 의존하지 않는 일반 데이터 액세스 코드를 작성할 수 있습니다.
DbProviderFactories 클래스는 DbProviderFactory 인스턴스를 만들기위한 정적 메서드를 제공합니다. 그런 다음 인스턴스는 런타임에 제공된 연결 문자열과 공급자 정보를 기반으로 올바른 강력한 형식의 개체를 반환합니다.
예:
DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();
/* Getting SqlClient family members */
DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbCommand dbCommand = dbProviderFactory.CreateCommand();
DbConnection dbConnection = dbProviderFactory.CreateConnection();
DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();
SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
SqlConnection sqlConnection = (SqlConnection)dbConnection;
SqlCommand sqlCommand = (SqlCommand) dbCommand;
SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;
/* Getting OracleClient family members*/
dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
dbCommand = dbProviderFactory.CreateCommand();
dbConnection = dbProviderFactory.CreateConnection();
dbDataAdapter = dbProviderFactory.CreateDataAdapter();
OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
OracleConnection oracleConnection = (OracleConnection)dbConnection;
OracleCommand oracleCommand = (OracleCommand)dbCommand;
OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;
구체적인 Factory 인스턴스는 아래와 같이 static Factory 방식으로 제공됩니다.
public class FurnitureProviderFactory
{
public static IFurnitureFactory GetFactory(string furnitureType)
{
if (furnitureType == "Wood")
{
return new WoodenFurnitureFactory();
}
if (furnitureType == "Plastic")
{
return new PlasticFurnitureFactory();
}
throw new Exception("Undefined Furniture");
}
}
a.jar을 만들고 다른 사람이 jar를 사용하고 코드에서 새로운 구체적인 객체를 사용하려고한다고 가정 해 보겠습니다. 추상 팩토리를 사용하지 않는 경우 코드를 수정하거나 코드를 덮어 써야합니다. 그러나 추상 팩토리를 사용하는 경우 팩토리를 제공하고 코드에 전달할 수 있으며 모든 것이 정상입니다.
개선 된 버전 : 다음 시나리오를 고려하십시오. 다른 사람이 프레임 워크를 작성했습니다. 프레임 워크는 추상 팩토리와 일부 구체적인 팩토리를 사용하여 런타임에 많은 개체를 만듭니다. 따라서 자신의 팩토리를 기존 프레임 워크에 쉽게 등록하고 자신 만의 개체를 만들 수 있습니다. 프레임 워크는 수정이 불가능하며 추상적 인 팩토리 패턴으로 인해 확장하기 쉽습니다.
이 패턴은 클라이언트가 생성 할 유형을 정확히 알지 못하는 경우 특히 유용합니다. 예를 들어 휴대폰만을 판매하는 쇼룸이 삼성에서 만든 스마트 폰에 대한 쿼리를받는다고 가정 해 보겠습니다. 여기서 우리는 생성 될 개체의 정확한 유형을 알지 못합니다 (전화에 대한 모든 정보가 구체적인 개체 형태로 래핑되었다고 가정). 그러나 우리는 삼성에서 제조 한 스마트 폰을 찾고 있다는 것을 알고 있습니다. 이 정보는 우리의 디자인에 Abstract Factory 구현이있는 경우 실제로 활용할 수 있습니다.