2014-01-30 3 views
3

Следующий код - это своего рода заводская модель для D, использующая шаблоны, что подразумевает создание легко подключаемых объектов.Static Factory Pattern

Как есть, код не является надежным (множественное наследование, зависимости и т. Д.).

Я бы хотел, чтобы он работал в более общих и общих настройках, таких как наличие определенного типа списка зависимостей для разных объектов/типов (я установил код для этого пути, используя 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; 
    } 

} 

ответ

1

в любом случае, может быть, кто-то имеет некоторые полезные идеи, чтобы получить меня в правильном направлении?

Вот некоторые из них:

  • Заканчивать Object.factory, что позволяет создать класс, используя только его полное имя.
  • В шаблонах mixin вы можете использовать typeof(this), что означает, что вам не нужно передавать тип текущего объекта в mixin в качестве параметра.
  • Я не вижу причин для static interface iStaticFactory, так как вы можете иметь несколько static this за класс.
  • Если ваша программа использует только один поток, то более подходящим будет shared static this, так как он будет регистрировать компоненты при запуске программы, а не в начале каждого потока.

Я также думаю, что есть, вероятно, каким-то образом обрабатывать сохранение и восстановление данных проще, но я не совсем уверен, как подойти к нему.

Я только что закончил капитальный ремонт my persistence module, возможно, вы найдете там что-то полезное (см. Примеры использования для использования).

+0

Спасибо. используется интерфейс istatic, так что статический это не переопределяется непреднамеренно. Если класс имеет значение static, и он не регистрирует класс, тогда класс не может использоваться при создании самого. Использование интерфейса просто гарантирует, что обработчики всегда зарегистрированы. – user3252407

+0

Я не думаю, что object.factory помогает здесь, потому что он не дает возможности инициализировать объект, а также, вероятно, использует GC для создания объектов. – user3252407

+0

Вы можете иметь столько статических конструкторов в классе, сколько хотите. Они не будут переопределять или конфликтовать друг с другом и будут работать в том порядке, в котором они объявлены. 'Object.factory' вызывает конструктор по умолчанию класса, который может выполнять любую инициализацию, в которой вы нуждаетесь. –