digitalmars.D.learn - Static Factory
- Frustrated (117/117) Jan 29 2014 (Guess is didn't get sent, I guess I'm just a big spam bot cause
(Guess is didn't get sent, I guess I'm just a big spam bot cause I keep getting flagged every post) The following code demonstrates a way to have an easy factory in D requiring very little work. I imagine it can be improved to handle the abstract case(basically dependencies/constraints). Any ideas on how to improve it? I think auto serialization of the data of the object will end up being the default behavior. One should be able to templatize the save/restore code. Once this is all done I would think very little work would be required in creating pluggable code(simply use the templates). module main; import std.file, std.stdio; // Mixin iStaticFactory into an interface to provide generic pluggable derived instantiation. // Must use New(id, data) as a way to instantiate a new object of type A(specified by ID) : T. New() is allowed but only provides // default type and is not pluggable. A msg is given anywhere New() is used(should only be used when pluggability is not desired) or during mock up. // // The corresponding mixin template cStaticFactory must be used in all derived types that are to be pluggable. // // The user must provide a way to store and retrieve the object data to allow generic and configurable pluggability. As is, // any derived type of T may be substituted for T dynamically.. mixin template iStaticFactory(T) { property string _getID(); // returns the type name for this object static final T function(string data)[string] _Creators; // An AA of functions that are registered by the classes which are desired to be plugged into the interface T. // Generic New function that returns an initiated instance of a derived type of T corresponding to data.ID. static final T New(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__)(string id, string data = null) { if (id != null &&_Creators[id] != null) return _Creators[id](data); return myA.New(null); // provides default type } // Non-Generic New function returning a default derived type of T used for testing purposes or default object static final T New(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__)() { pragma(msg, "StaticFactory: Not pluggable at "~mod~":"~std.string.chomp(line.stringof, "u")~" ["~file~"]"); return New(null); } } // Mixin cStaticFactory into any class A derived from interface T to allow it to be pluggable. Mixin static final A New to provide data initialization of object. mixin template cStaticFactor(A, T) if (is(A : T)) { enum _ID = std.traits.fullyQualifiedName!A; property string _getID() { return _ID; } // Registers this class with the _Creators of T's StaticFactory allowing it to be used to create it's own type. (interface is only used to ensure the class is registered at runtime. Could be done elsewhere or dynamically) static interface iStaticFactory { static this() { T._Creators[_ID] = &New; } } // Creates and instantiates this type with data. Override to instantiate data. static final T New(string data) { A t = new A; if (data == null) return t; return t; } } // Demo: interface A { mixin iStaticFactory!A; void foo(); } class myA : A { mixin cStaticFactor!(myA, A); void foo() { writeln("-------Called from myA"); } } class otherA : A { mixin cStaticFactor!(otherA, A); void foo() { writeln("------------Called from otherA"); } } void main() { enum fn = "tempSFdata.tmp"; // load/create our object. A a = A.New(exists(fn) ? cast(string)read(fn, 100) : null); // Display object's typeDo something with the object writeln("Current object type is "~a._getID~" with output :"); a.foo(); // Provide mechanism to change object foreach(k, v; A._Creators) { if (k == a._getID) continue; writeln("Would you like to change to "~k~" [y/n]"); if (readln() == "n") continue; // Set a to new object type, assume no data a = v(null); std.file.write(fn, a._getID); writeln("Changed to "~k~""); break; } }
Jan 29 2014