[Źródło: https://docs.microsoft.com/en-us/dotnet/]
Głównym zadaniem fabryk jest stworzenie nadrzędnej klasy odpowiedzialnej za tworzenie nowych obiektów. Przez co uzyskuje się łatwiejsze zmiany
Metoda fabrykująca (ang. Factory Method):
Jej zadaniem jest stworzenie pojedynczego obiektu. Klasa z taką metodą będzie zwracać tylko konkretny stworzy obiekt. Dodatkowo w przypadku wykorzystania metody wytwórczej klasa tworząca obiekt nie dziedziczy po innej klasie bądź interfejsie.
Metoda ta jest przydatna gdy chcemy stworzyć podobne elementy jednego typu.
Poniżej opiszę prosty przykład realizujący opisany przykład.
Na samym początku definiujemy klasę główną w której główny konstruktor będzie zdefiniowany jako prywatny.
Teraz do klasy dodajemy konstruktory publiczne, które pozwolą w różny sposób stworzyć nowy obiekt klasy.
Teraz w celu stworzenia nowego obiektu z zmodyfikowanymi parametrami należy wywołać:
Metoda ta jest przydatna gdy chcemy stworzyć podobne elementy jednego typu.
Poniżej opiszę prosty przykład realizujący opisany przykład.
Na samym początku definiujemy klasę główną w której główny konstruktor będzie zdefiniowany jako prywatny.
- public class FactoryClass
- {
- private UInt64 Data1;
- private UInt64 Data2;
- private FactoryClass(UInt64 data1, UInt64 data2)
- {
- this.Data1 = data1;
- this.Data2 = data2;
- }
- }
Teraz do klasy dodajemy konstruktory publiczne, które pozwolą w różny sposób stworzyć nowy obiekt klasy.
- public static FactoryClass newFactoryObject1(UInt64 data1, UInt64 data2)
- {
- return new FactoryClass(data1, data2);
- }
- public static FactoryClass newFactoryObject2(UInt64 data1, UInt64 data2)
- {
- return new FactoryClass((data1 * 10 - 7), (data1 * 7 - 10));
- }
Teraz w celu stworzenia nowego obiektu z zmodyfikowanymi parametrami należy wywołać:
- FactoryClass newFactoryClass_1 = FactoryClass.newFactoryObject1(34221383, 98749236);
- FactoryClass newFactoryClass_2 = FactoryClass.newFactoryObject1(87698346, 41236314);
Można także wyciągnąć metody tworzące do osobnej wewnętrznej klasy. Przez co ciągle będzie możliwość używania prywatnego konstruktora.
- public class FactoryClass
- {
- private UInt64 Data1;
- private UInt64 Data2;
- private FactoryClass(UInt64 data1, UInt64 data2)
- {
- this.Data1 = data1;
- this.Data2 = data2;
- }
- public class FactoryCreateClass
- {
- public static FactoryClass newFactoryObject1(UInt64 data1, UInt64 data2)
- {
- return new FactoryClass(data1, data2);
- }
- public static FactoryClass newFactoryObject2(UInt64 data1, UInt64 data2)
- {
- return new FactoryClass((data1 * 10 - 7), (data1 * 7 - 10));
- }
- }
- }
- public MainFactoryClass CreateFactoryType(ChildClass_Type type, UInt16 value)
- {
- MainFactoryClass test = null;
- if (type == ChildClass_Type.type1)
- {
- return (test = new ChildClass(value));
- }
- else if (type == ChildClass_Type.type2)
- {
- return (test = new ChildClass2(value));
- }
- return null;
- }
Klasy tworzące osobny obiekt:
- public class ChildClass : MainFactoryClass
- {
- private UInt16 Val;
- public ChildClass(UInt16 value)
- {
- this.Val = value;
- }
- }
- public class ChildClass2 : MainFactoryClass
- {
- private UInt16 Val;
- public ChildClass2(UInt16 value)
- {
- this.Val = value;
- }
- }
Fabryka abstrakcyjna (ang. Abstract Factory):
Fabryka abstrakcyjna działa na zasadzie wytworzenia interfejsu, który pozwala na stworzenie instancji abstrakcyjnych obiektów.
- public interface MainTypeInterface
- {
- void UseFunction();
- }
Następnie tworzymy główne klasy danych typów:
- internal class KindOfMainType1 : MainTypeInterface
- {
- public void UseFunction()
- {
- }
- }
- internal class KindOfMainType2 : MainTypeInterface
- {
- public void UseFunction()
- {
- }
- }
Kolejnym elementem jest przygotowanie interfejsu wraz z klasami fabryk:
- public interface MainTypeInterfaceFactory
- {
- MainTypeInterface UseFunction_2();
- }
- internal class KindOfMainType1_Factory : MainTypeInterfaceFactory
- {
- public MainTypeInterface UseFunction_2()
- {
- return new KindOfMainType_1();
- }
- }
- internal class KindOfMainType2_Factory : MainTypeInterfaceFactory
- {
- public MainTypeInterface UseFunction_2()
- {
- return new KindOfMainType2();
- }
- }
Dla tak przygotowanego zestawy klas przygotowujemy klasę odpowiedzialną za wytworzenie poszczególnych typów z zadanymi parametrami. Na samym początku należy zdeklarować rodzaje typów np. za pomocą enum:
- public enum AvailableType
- {
- Type1, Type2
- }
- private Dictionary<AvailableType, MainTypeInterfaceFactory> factories =
- new Dictionary<AvailableType, MainTypeInterfaceFactory>();
Konstruktor klasy ma za zadanie odczytanie zdeklarowanych typów i dodanie ich do słownika:
- public PrepareNewType()
- {
- foreach (AvailableType type in Enum.GetValues(typeof(AvailableType)))
- {
- var factory = (MainTypeInterfaceFactory)Activator.CreateInstance(
- Type.GetType("WpfThingSpeak." + "KindOfMain" + Enum.GetName(typeof(AvailableType), type) + "_Factory"
- ));
- factories.Add(type, factory);
- }
- }
Poniższa funkcja ma zadanie zwrócić zdeklarowany do zainicjalizowania typ:
- public MainTypeInterface GetSelectedTypeNewType(AvailableType type)
- {
- return factories[type].UseFunction_2();
- }
Cała klasa wygląda następująco:
- public class PrepareNewType
- {
- public enum AvailableType
- {
- Type1, Type2
- }
- private Dictionary<AvailableType, MainTypeInterfaceFactory> factories =
- new Dictionary<AvailableType, MainTypeInterfaceFactory>();
- public PrepareNewType()
- {
- foreach (AvailableType type in Enum.GetValues(typeof(AvailableType)))
- {
- var factory = (MainTypeInterfaceFactory)Activator.CreateInstance(
- Type.GetType("WpfThingSpeak." + "KindOfMain" + Enum.GetName(typeof(AvailableType), type) + "_Factory"
- ));
- factories.Add(type, factory);
- }
- }
- public MainTypeInterface GetSelectedTypeNewType(AvailableType type)
- {
- return factories[type].UseFunction_2();
- }
- }