Frage

Was ist ein eleganter Weg, um den Code von unter, wo ich mag eine abgeleitete Klasse zurückzukehren basierend auf der Art einer anderen Klasse.

            if (option_ is Rectangle)
            {
                modelInputs = new Foo();
            }
            else if (option_ is Circle)
            {
                modelInputs = new Bar();
            }
            else if (option_ is Triangle)
            {
                modelInputs = new Bar2();
            }
War es hilfreich?

Lösung

Haben Sie Rechteck, Kreis und Dreieck implementieren IHasModelInput:

interface IHasModelInput
{
    IModelInput GetModelInput();
}

dann können Sie tun,

IModelInput modelInputs = option_.GetModelInput();

Andere Tipps

Meine Meinung: Ihre „unelegant“ Art und Weise ist in Ordnung. Es ist einfach, lesbar und macht den Job.

Mit dem Rechteck, Kreis und Dreieck implementieren die notwendige Fabrik-Funktion über IHasModelInput funktionieren würde, aber es hat ein Design Kosten: Sie haben jetzt gekoppelt diesen Satz von Klassen mit dem IModelInput Satz von Klassen ( foo, Bar und Bar2). Sie konnten in zwei völlig verschiedenen Bibliotheken sein, und vielleicht sollten sie wissen, nicht übereinander.

Ein komplizierteres Verfahren ist unten. Es gibt Ihnen den Vorteil, in der Lage, Ihre Fabrik Logik zur Laufzeit zu konfigurieren.

    public static class FactoryMethod<T>  where T : IModelInput, new()
    {
        public static IModelInput Create()
        {
            return new T();
        }
    }

    delegate IModelInput ModelInputCreateFunction();

    IModelInput CreateIModelInput(object item)
    {

        Dictionary<Type, ModelInputCreateFunction> factory = new Dictionary<Type, ModelInputCreateFunction>();


        factory.Add(typeof(Rectangle), FactoryMethod<Foo>.Create);
        factory.Add(typeof(Circle),    FactoryMethod<Bar>.Create);
        // Add more type mappings here




        IModelInput modelInput;
        foreach (Type t in factory.Keys)
        {
            if ( item.GetType().IsSubclassOf(t) || item.GetType().Equals(t))
            {
                modelInput = factory[t].Invoke();
                break;
            }
        }
        return modelInput;
    }

Aber dann stellt die Frage: welche würden Sie lieber lesen

Sie können die Ein- und Ausgänge in einer Hashtable setzen, oder die Typen speichern, die jede Klasse innerhalb jeder der Klassen erstellen Sie erstellen und dann Activator.CreateInstance verwenden, um die factoryin zu tun:

Hashtable ht = new Hashtable();
ht.Add(typeof(Rectangle), typeof(Bar));
ht.Add(typeof(Square), typeof(Bar2));

modelInputs = Activator.CreateInstance(ht[option.GetType()]);

So oder so ist Activator.CreateInstance eine ziemlich coole Art der Fabriken in .NET arbeiten. Genießen und nutzen die Kraft habe ich Sie mit Bedacht gegeben, mein Sohn.

Sie können einen Typ mit „option_“ assoziieren, wenn es erlaubt, und dann nur eine Instanz davon erstellen.

ich in der Regel eine Factory-Methode wie folgt verwenden, wenn ich einen String in einen Typ zur Laufzeit konvertieren wollen, verwende ich ein Wörterbuch, die eine Zeichenfolge an einen Typ zuordnet.

Wie dies aus einem aktuellen Projekt:

public class TaskFactory
{
    private Dictionary<String, Type> _taskTypes = new Dictionary<String, Type>();

    public TaskFactory()
    {
        // Preload the Task Types into a dictionary so we can look them up later
        foreach (Type type in typeof(TaskFactory).Assembly.GetTypes())
        {
            if (type.IsSubclassOf(typeof(CCTask)))
            {
                _taskTypes[type.Name.ToLower()] = type;
            }
        }
    }

    public CCTask CreateTask(XmlElement task)
    {
        if (task != null)
        {
            string taskName = task.Name;
            taskName =  taskName.ToLower() + "task";

            // If the Type information is in our Dictionary, instantiate a new instance of that task
            Type taskType;
            if (_taskTypes.TryGetValue(taskName, out taskType))
            {
                return (CCTask)Activator.CreateInstance(taskType, task);
            }
            else
            {
                throw new ArgumentException("Unrecognized Task:" + task.Name);
            }                               
        }
        else
        {
            return null;
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top