Laden...

Was genau ist der Vorteil vom Factory-Pattern?

Erstellt von JimStark vor 3 Jahren Letzter Beitrag vor 3 Jahren 753 Views
JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren
Was genau ist der Vorteil vom Factory-Pattern?

Hi,

von .NET Entwicklern hört man ja recht oft "new is glue", deswegen wollte ich mich da auch mal etwas weiterbilden 😄

Ich habe mal versucht ein einfaches Factory-Pattern umzusetzen. Es sollen (hier als Beispiel) Aktien aus verschiedenen Quellen importiert werden können (Xml, Json, Api,...).


    // Product:
    public abstract class StockImporter
    {
        public abstract List<Stock> GetStocks();
    }

    // ConcreteProduct:
    public class XmlStockImporter : StockImporter
    {
        public string _file;
        public XmlStockImporter(string fileLocation)
        {
            _file = fileLocation;
        }
        public override List<Stock> GetStocks()
        {
            // lese XML _file...
            return new List<Stock>();
        }
    }

    // Creator:
    public abstract class StockImporterFactory
    {
        public abstract StockImporter GetStockImporter();
    }

    // ConcreteCreator:

    public class XmlStockImporterFactory : StockImporterFactory
    {

        private string _Location;

        public XmlStockImporterFactory(string location)
        {
            _Location = location;
        }
        public override StockImporter GetStockImporter()
        {
            return new XmlStockImporter(_Location);
        }

    }

Möchte ich jetzt den XmlImporter nutzen würde ich den mit meinem Kenntnisstand so erstellen:


var factory = new XmlStockImporterFactory("C:/test.xml");
StockImporter importer = factory.GetStockImporter();
var stocks = import.GetStocks()...

Ich verstehe jetzt nicht genau was da der Vorteil ist, außer dass ich nicht direkt den XmlStockImporter erzeugen muss. Soll die Factory das "Erzeugen" übernehmen, dass ich bei aufwendigeren DIs mich nur in der Factory kümmere?

Zweite Frage:
Theoretisch bräuchte ich jetzt doch noch eine Factory oder gibt es da eine schönere Lösung?
Z.B. sowas:


public enum StockImporterType ...

public StockImporterFactoryProvider(StockImporterType type)
{
    select(....) // jeweiligen Typ zurückgeben
}

W
955 Beiträge seit 2010
vor 3 Jahren

Das verstehe ich nicht... Warum verwendest du nicht einfach Dependency injection? Ansonsten würde ich an deiner Stelle die verschiedenen Erzeugungsmuster mal anschauen, da gibt es verschiedene Abstraktionsstufen.

16.806 Beiträge seit 2008
vor 3 Jahren

Dein Code Beispiel entspricht nicht dem Sinn einer Factory; daher vermutlich das Verständnisproblem.

Wie witte schon gesagt hat, gibt es bei Factories verschiedene Stufen; alle zusammen verfolgen aber den Sinn die Instanziierung abstrakt umzusetzen.
Die am meisten verbreiteten Varianten sind die Vererbung- und die Typ-Implementierung:

Vererbung

namespace MyCSharp
{
    public interface IFahrzeug { }

    public abstract class FahrzeugFactory
    {
        public abstract IFahrzeug GetFahrzeug();
    }

    public class Auto : IFahrzeug { }

    public class AutoFactory : FahrzeugFactory
    {
        public override IFahrzeug GetFahrzeug() => new Auto();
    }
}

Typ
Wenn also jemand ein Fahrzeug braucht und die konkrete Implementierung egal ist, dann gibt es absolut null Abhängigkeit a) zum Typ und b) zur Erzeugung.

namespace MyCSharp
{
    public interface IStockTickerSymbolService
    {
        Task<SymbolData> GetSymbolData(string symbol);
    }
    public class ComdirectStockTickerOptions
    {
        public string SymbolUrl = "https://www.comdirect.de/inf/aktien/{0}";
    }
    public class YahooStockTickerSymbolService : IStockTickerSymbolService
    {
        public YahooStockTickerSymbolService(IOptions<YahooStockTickerOptions> optionsAccessor)
    }
    public class ComdirectStockTickerSymbolService : IStockTickerSymbolService
    {
        public ComdirectStockTickerSymbolService(IOptions<ComdirectStockTickerOptions> optionsAccessor)
    }
}

Beispiel aus: Mit welchem Pattern kann ich generische Links zu versch. (Finanz)Websites herstellen?
Haste aber sicher schon bei Deiner entsprechenden Suche als 4. Treffer (3 Wochen alt) hier im Forum entdeckt.

Im anderen weit verbreiteten Fall hat man die Information, was man erzeugen will, aber nicht das Wissen, um es selbst zu erzeugen (hier die Optionen).

Im Falle von einem Stockticker will ich zB. Informatioinen über eine Aktie haben, die prinzipiell bei jeder API identisch im Format zu haben sind; die API wird aber unterschiedliche angesprochen.

Brauchst dann quasi nur noch die Implementierung, dass Du anhand zB. eines Enum die Instanz von Yahoo oder eben ComDirect bekommst.
Das siehst Du im Beispiel des 5. Treffers aus Deiner sicherlich durchgeführten Forensuche

Tipp zur Implementierung auswählbarer Hardware API (static class methoden auswählbar)

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Danke euch beiden für die Antworten.

Dein Code Beispiel entspricht nicht dem Sinn einer Factory; daher vermutlich das Verständnisproblem.

Was ist daran falsch, hatte mich sogar an deinem von dir verlinkten Artikel orientiert:
https://www.dofactory.com/net/factory-method-design-pattern
Verstehe da nicht ganz den Unterschied zu deinem Beispiel außer dem Interface.

Also eine Methode mit einem Switch & enum als Parameter, die mir dann die ConcreteFactory (z.B. AutoFactory) zurückgibt wäre auch eine Factory?

T
2.219 Beiträge seit 2008
vor 3 Jahren

In dem Fall ist das Problem, dass du in deinem Code bereits die konkrete Factory erstellst und und verwendest.

Der Sinn der Factory ist es, dass man eben nicht gegen eine konkrete Implementierung arbeitet sondern gegen das Interface und somit eine austauschbare Basis hat.
Damit kann man wie bei einer Fabrik eben gemeinsame Typen erstellen und diese über ein Interface nutzen und austauschen.
Dadurch muss man auch nicht wissen, wie ein konkreter Typ instanziert wird.
Diese Details können dann auch im Hintergrund verborgen bleiben, was für den Verbraucher i.d.R. egal ist.

Der Verbraucher einer Factory muss dann nur den entsprechenden Typen anfordern, erhält auf seiner Seite dann nur eine Implementierung des Interface.
Dadurch muss der Anwender auch nicht wissen welcher Konkrete Typ vorliegt, solange dieser das zu grunde liegende Interface umsetzt.

Klarer wird es wenn man mit der Factory Method anfängt.
Dort hast du dann eine Methode, die dein Interface liefert.
Per Parameter steuerst du dann, welcher konkrete Typ geliefert werden muss.
Ob das dann ein Enum, string, int oder was auch immer ist, hängt von der jeweiligen Implementierung ab.
Der Verbraucher bekommt dann immer nur sein Interface gegen das er arbeitet.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Danke T-Virus.

Ich glaube ich habe es soweit verstanden, der Factory übergebe ich dann z.B. meine Configuration, die Factory kümmert sich dann um die Erzeugung des gewünschten Products und weiß z.B. welche Section für die jeweilige Options genutzt wird und übergibt sie dem Product/erzeugt es.

Danke euch!