如何通过脚本在DigitalMicrograph中设置持久性协作对象?

时间:2014-11-20 21:18:18

标签: oop design-patterns dm-script

我非常欣赏使用对象通过DMS语言在DigitalMicrograph环境中部署给定应用程序的好处。面向对象的方法打开了使用涉及协作对象的可重用设计模式的大门,例如,模型 - 视图 - 控制器(MVC)。但是,由于使用自动引用计数来管理其生命周期,因此DM中的对象似乎具有高度不稳定性。为了使MVC三元组或任何其他协作对象集合保持足够长的时间以使其有用,它们中的至少一个必须植根于由DM应用程序管理的非易失性对象。到目前为止,我在DM中遇到的唯一这样的对象是基于UIFrame类的对象(即无模式对话框和UI调色板)。对于MVC实现,这很好用,因为将View实现为UIFrame对象是有意义的。它只是有点不同寻常,因为View对象成为保持MVC三重奏活着并运行的根对象。通常,它是Controller对象,它以应用程序为根,管理Model和View对象。但是那些不涉及UI的设计模式呢?是否有任何(可接受的)方法来提供一组协作对象持久性而不将它们植入UIFrame对象中?是否有其他可应用于此目的的应用程序根对象类型?我认为由于不可避免的内存泄漏风险,建立一个参考周期不是一种可接受的方法。

3 个答案:

答案 0 :(得分:1)

我可以想出各种方法来获得这种持久性,但首先想到的是将一个对象引入后台线程,如下例所示。如果对象仍然存在,实际的后台线程可以经常检查,并且通过与外部世界共享对象ID,其他对象(不必是持久的)可以访问“锚定”对象。

尽管如此警告:如果你把这些内容保存在内存中,关闭DigitalMicrograph时一定要小心。如果对象挂起了DM想破坏的一些项目,你可能会在最后看到错误或崩溃。

// This is the object "anchored". It will remain in memory, because we launch it on a separate thread.
// On this thread, it loops until a variable is set to false (or until SHIFT is pressed)
Class IPersist : Thread
{
    number keepme

    IPersist( object self ) { result("created IPersist:"+self.ScriptObjectGetID()+"\n");}
    ~IPersist( object self ) { result("killed IPersist:"+self.ScriptObjectGetID()+"\n\n\n\n");}

    void CallFromOutside( object self ) { Result( "\t IPersist can be used!\n" ); }
    void StopFromOutside( object self ) { keepme = 0; }
    void RunThread( object self )
    {
        keepme = 1
        Result( "\t Called once at start.\n")
        While( keepme && !ShiftDown() ) yield()
        Result( "\t Finished.\n")
    }
}

// Just and example class used to access the 'anchored' object
Class SomethingElse
{
    number keepID
    SomethingElse( object self ) { result("created SomethingElse:"+self.ScriptObjectGetID()+"\n");}
    ~SomethingElse( object self ) { result("killed SomethingElse:"+self.ScriptObjectGetID()+"\n");}
    void SetKeepID( object self, number id ) { keepID = id; }
    void CallOut( object self )
    {
        result( "SomethingElse object is accessing CallOut...\n" )
        object p = GetScriptObjectFromID( keepID )
        if ( p.ScriptObjectIsValid() )
        {
            p.CallFromOutside()
        }
    }
    void CallStop( object self )
    {
        result( "SomethingElse object is accessing CallOut...\n" )
        object p = GetScriptObjectFromID( keepID )
        if ( p.ScriptObjectIsValid() )
        {
            p.StopFromOutside()
        }
    }
}


// Main script. Create object on separate thread. Then feed it's ID as "weak reference" into the second object.
{
    object ob = Alloc(IPersist)
    ob.StartThread()    

    object other = Alloc(SomethingElse)
    other.SetKeepID( ob.ScriptObjectGetID() )
    other.CallOut()
    If ( TwoButtonDialog( "You can either stop IPerstis now, or by pressing SHIFT later.", "Stop now", "later" ) )
        other.CallStop()
}

答案 1 :(得分:1)

另一种方法是让两个对象保持彼此的引用。这是一种通常宁可避免的死锁情况,但为了锚定,它也可以起作用。在您故意释放对象之前,任何对象都不会超出范围。 同样,您有责任发布'当你想要正确关闭系统时的事情。

死锁情况的代码相当渺茫:

class SelfLock
{
    object partner
    SelfLock( object self ) { result("created SelfLock:"+self.ScriptObjectGetID()+"\n");}
    ~SelfLock( object self ) { result("killed SelfLock:"+self.ScriptObjectGetID()+"\n");}
    void SetPartner(object self, object p) { partner = p; }
    void ReleasePartner(object self) { partner = NULL; }
}


{
    object p1 = Alloc(SelfLock)
    object p2 = Alloc(SelfLock)
    p1.SetPartner(p2)
    p2.SetPartner(p1)

    if ( TwoButtonDialog( "Release partner", "Yes", "No keep locked" ) )
        p1.ReleasePartner()
}

答案 2 :(得分:1)

第三种,也是迄今为止最好,最干净的解决方案是将你的对象作为一个“倾听者”来启动。对某些事件。当您正在寻找一个只要DigitalMicrograph打开时应该保持在范围内的对象,它可能最好听取应用程序本身。通过倾听" about_to_close"消息,你也可以获得在关机前正确释放所有资源的理想句柄。代码如下:

从我的3个答案中,我将使用这个答案。 (其他人应该只是说明选项。)

class MyPermanentObject 
{
    MyPermanentObject( object self ) { result("created MyPermanentObject :"+self.ScriptObjectGetID()+"\n");}
    ~MyPermanentObject( object self ) { result("killed MyPermanentObject :"+self.ScriptObjectGetID()+"\n");}
    void DeInitialize( object self, number eventFlags, object appObj ) 
    { 
        OKDialog( "The application is closing now. Deinitialize stuff properly!" ); 
    }
}


{
    object listener = Alloc( MyPermanentObject )
    ApplicationAddEventListener( listener, "application_about_to_close:DeInitialize" )
}