design-patterns - 静态工厂模式

标签 design-patterns d

以下代码是一种使用模板的 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;
    }

}

最佳答案

Anyways, maybe someone has some useful ideas to get me in the right direction?

这里有几个:

  • 查看 Object.factory ,它允许仅使用其完全限定名称创建一个类。
  • 您可以在混入模板中使用typeof(this),这意味着您不需要将当前对象的类型作为参数传递给混入。
  • 我看不出有任何理由需要static interface iStaticFactory,因为每个类可以有多个static this
  • 除非您的程序只使用一个线程,否则 shared static this 会更合适,因为它将在程序启动时注册组件,而不是在每个线程启动时。

I also think that there is probably some way to handle the saving and restoring of data easier but I'm not quite sure how to approach it.

我刚刚完成了对 my persistence module 的大修,也许您可​​以在那里找到有用的东西(有关使用示例,请参阅单元测试)。

关于design-patterns - 静态工厂模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21452759/

相关文章:

c++ - 在没有派生类先验知识的情况下,有没有更好的方法来定义访问者模式?

java - 根据对象实例显示自定义编辑器的设计模式是什么?

java - 在访问者界面中不指定所有派生类型的情况下实现访问者模式?

design-patterns - 软件中使用的设计模式有哪些现实生活中的例子

d - D语言中的"With" block

multithreading - x86 上的字撕裂

c# - 处理对象状态的适当方式?

d - 为什么我必须投这个?

set - D中的简单集实现?

concurrency - D 中有等价的 goroutines 吗?