以下代码是D使用模板的一种工厂模式,这意味着可以轻松地制作可插拔对象。
原样,代码不健壮(多重继承,依赖等)。
我希望它能够在更通用和更常见的设置中工作,例如为不同的对象/类型设置某种类型的依赖列表(我已经使用gui设置代码沿着该路径)按钮场景)。
我也认为可能有一些方法可以更轻松地处理数据的保存和恢复,但我不太清楚如何处理它。让每个对象序列化它的数据并将其存储在数据库中还是只有一个全局存储来处理它? (我认为只存储默认值的变化很重要)
无论如何,也许有人有一些有用的想法让我朝着正确的方向前进?
(因为代码与使用工厂几乎相同,因为任何iGui实现都可以插入。我称之为静态工厂模式,因为所有设置都是在幕后完成的,主要是在编译时(通过模板) ))
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.
//
// D is the default object type to use
mixin template iStaticFactory(D)
{
alias T = typeof(this);
static assert(is(D : typeof(this)), "iStaticFactory: "~std.traits.fullyQualifiedName!(D)~" must inherit from "~std.traits.fullyQualifiedName!(typeof(this)));
@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 && id in _Creators) return _Creators[id](data);
return D.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 to provide pluggability.
mixin template cStaticFactor()
{
alias A = typeof(this);
// Assume if A has a _Creators member, New member, and _getID member then it inherits from an interface using iStaticFactory
static assert(std.traits.hasMember!(A, "_Creators") & std.traits.hasMember!(A, "New") & std.traits.hasMember!(A, "_getID"), "cStaticFactory: "~std.traits.fullyQualifiedName!(A)~" must inherit from a Static Factory!");
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.
static this() { A._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 iGui { mixin iStaticFactory!(WindowsGui); void foo(); }
class WindowsGui : iGui { mixin cStaticFactor; void foo() { writeln("-------Called from "~std.traits.fullyQualifiedName!(typeof(this))); } }
class LinuxGui : iGui { mixin cStaticFactor; void foo() { writeln("-------Called from "~std.traits.fullyQualifiedName!(typeof(this))); } }
interface iButton { mixin iStaticFactory!(WindowsButton); void foo(); }
class WindowsButton : iButton { mixin cStaticFactor; void foo() { writeln("-------Called from "~std.traits.fullyQualifiedName!(typeof(this))); } }
class LinuxButton : iButton { mixin cStaticFactor; void foo() { writeln("-------Called from "~std.traits.fullyQualifiedName!(typeof(this))); } }
void main()
{
import std.traits;
enum fnGui = "guiSFdata.tmp";
enum fnButton = "butSFdata.tmp";
// load/create our gui object.
iGui a = iGui.New(exists(fnGui) ? cast(string)read(fnGui, 100) : null);
// Display object's typeDo something with the object
writeln("Current object type is "~a._getID~"["~(exists(fnGui) ? cast(string)read(fnGui, 100) : "new")~"] with output :");
a.foo();
// Provide mechanism to change object
foreach(k, v; iGui._Creators)
{
if (k == a._getID) continue;
writeln("Would you like to change to "~k~" [y/n]"); if (readln()[0] == 'n') continue;
// Set a to new object type, assume no data
a = v(null);
std.file.write(fnGui, a._getID);
writeln("Changed to "~k~"");
break;
}
}
答案 0 :(得分:1)
无论如何,也许有人有一些有用的想法让我朝着正确的方向前进?
以下是一些:
typeof(this)
,这意味着您无需将当前对象的类型作为参数传递给mixin。static interface iStaticFactory
没有任何理由,因为每个课程可以有多个static this
。shared static this
会更合适,因为它会在程序启动时注册组件,而不是在每个线程的启动时注册。我也认为可能有一些方法可以更轻松地处理数据的保存和恢复,但我不太清楚如何处理它。
我刚刚完成my persistence module的大修,也许你可以在那里找到有用的东西(参见单元测试的用法示例)。