ITPub博客

首页 > IT职业 > IT生活 > 摘录: NewEdit/doc/architecture.htm

摘录: NewEdit/doc/architecture.htm

原创 IT生活 作者:1000copy 时间:2007-03-31 08:10:07 0 删除 编辑

----------------评价

可以达到的一个效果就是:一个changelog的版本修改记录,可以完全确定修改对应的源代码文件。

好与坏还需要权衡。但是仅仅一一点,就让人有尝试的愿望了。

----------------原文

软件开发是一件很痛苦的事情,大量新的需求与现有软件结构之间的冲突是造成软件难以维护的一个主要原因。很 多软件在刚开始时可能结构很好,便于扩充,但随着软件功能的丰富,代码的增加,可能会造成结构也变得不再适应 新需求的发展。对于编辑器软件来说,这样的问题更为明显。那么NewEdit就是想在如何构造一种灵活的结构方面进 行的一种有益地探索,同时它会发展成为一个专业、稳定地编辑器软件。因此,NewEdit的设计核心就是,如何构造一 种灵活的架构,使得新功能的增加更为方便和易于维护。

NewEdit使用的软件基础是Python+wxPython。因此,NewEdit可以充分地享受Python的动态特性所带来的好处,同 时由于使用了wxPython,还可以实现跨平台的运行。

这样,NewEdit的设计思想就是充分利用Python语言的动态特性,构造易于扩充而又灵活的软件体系。具体的实现技术 就是全部采用Mixin和Plugin的设计与开发方法,更为通俗地说法就是分布式类编程技术,或狭义地理解为插件编程 (但分布式类编程与插件编程是不同的,分布类编程包括Mixin和Plugin,而插件编程一般只包括Plugin,因此插件编程 的功能扩展是有局限的)。有时为了简单,我会叫分布类编程为Mixin,具体到技术细节时,会细分Mixin和Plugin。

比如,软件刚开始还是一个雏形,可能只有少数的功能。因此,会有一些实现了基础功能的类。当这些基础功能稳定,同 时有新的需求时,这时需要对这些类进行扩展。扩展基本分为两种:

  1. 新的方法、属性的实现
  2. 增加对新方法、属性的调用入口

对于无法通过新的方法、属性实现的可能还需要增加新的类。此时可以对现有的类采用第二种扩展从而实现原有类与新 类之间的联系。

知道了扩展方式,那么在哪里去实现呢?对于第1种扩展,我的方法是,基本不动原来的类所在的文件,而是创建一个 新的文件,在这个新文件中实现新的方法、属性。然后通过一种机制把新的方法和属性与目标类进行融合,同时这种融 合是在运行时才实现的。这样,一个类的功能是随着开发的进行,不停地进行扩展。由于新的扩展并不是直接在原来的 文件中进行地修改,并且在一个文件中可以同时对多个类进行扩展,因此相对容易地知道本次扩展都做了哪些工作,对 于软件的维护非常方便。这些扩展会通过一种机制,在软件运行时自动与目标类进行融合,不需要做额外的工作。对于 这种扩展,我叫它为Mixin扩展。对于第2种扩展,我的方法是,在原来的类中增加相应的调用接口,同时在Mixin扩展 中增加对调用接口的具体实现,从而通过调用接口将新增的功能与原类联系起来。对于这种扩展我叫它为Plugin扩展, 也可以叫做插件扩展。

因此Mixin扩展的开发主要是对目标类进行功能扩展,如增加新的类方法,修改类方法,增加新的属性等。对于Plugin 扩展主要是在目标类中需要寻找合适的调用位置,定义相应的调用接口。同时实现具体的Plugin实现代码。

这里还存在的一个要考虑的问题是,Plugin扩展要根据具体情况考虑是否需要实现。首先,实现Plugin是因为新增的方法、 属性的使用不会自动完成,需要一个调用点。如果你扩展的方法属合某种事件机制的调用规则,那么可以不用实现Plugin接 口,否则就要实现相应的Plugin接口。

下面举一个例子,来看一下两种扩展的实现。其中有些具体的细节还没有涉及,后面会讲到:

class MainFrame(wx.Frame):
def __init__(self, parent, title='Test'):
wx.Frame.__init__(self, parent, -1, title=title)

上面是一个窗体,这可能就是我们的雏形。现在我们想在上面增加一个按钮,并对按钮事件进行响应。我们可以直接在 MainFrame上修改。如果这个类很简单当然可以,但如果这个类很复杂,并且一次改动不止要改动一个地方,就不是一件 容易的事情了。现在我们使用Mixin的方法来做。

  1. 如果想使一个类可以实现分布类编程,那么需要使它成为Mixin类,我定义它为Slot类(槽类),那么它就是一个目标 类,将被进行Mixin扩展。改造MainFrame类如下:

    import Mixin
    import wx

    class MainFrame(wx.Frame, Mixin):
    __mixinname__ = 'mainframe'

    def __init__(self, parent, title='Test'):
    self.initmixin()
    wx.Frame.__init__(self, parent, -1, title=title)

改造很简单,使得MainFrame有一个Mixin的基类,定义一个类属性__mixinname__,如: mainframe,在__init__中调 用self.initmixin()。这样,我们就把一个MainFame改造成了一个槽类。

  1. 创建一个新文件,将用于实现具体的扩展。内容如下:

    import Mixin
    import wx

    def init(win):
    win.ID_CLICK = wx.NewId()
    win.btnClick = wx.Button(win, win.ID_CLICK, 'Click Me')
    wx.EVT_BUTTON(win.btnClick, win.ID_CLICK, win.OnClick)

    def OnClick(win, event):
    print 'Click Me'
    win.Close()

可以看出我们在新文件中实现了两个方法,一个用来创建一个按钮,并且设置当单击按钮时,调用OnClick事件处理函数。另一个就是 OnClick事件处理函数。如果我们不使用Mixin扩展,那么这两个函数可能是这样:

import wx

class MainFrame(wx.Frame):

def __init__(self, parent, title='Test'):
wx.Frame.__init__(self, parent, -1, title=title)
self.ID_CLICK = wx.NewId()
self.btnClick = wx.Button(self, self.ID_CLICK, 'Click Me')
wx.EVT_BUTTON(self.btnClick, self.ID_CLICK, self.OnClick)

def OnClick(self, event):
print 'Click Me'
self.Close()

可以看出,OnClick其实是MainFrame的成员方法,而init应该位于__init__中,是__init__中的一段处理。如果使用Mixin应该如何写呢? 结果是:

import Mixin
import wx

def init(win):
win.ID_CLICK = wx.NewId()
win.btnClick = wx.Button(win, win.ID_CLICK, 'Click Me')
wx.EVT_BUTTON(win.btnClick, win.ID_CLICK, win.OnClick)
Mixin.setPlugin('mainframe', 'init', init)

def OnClick(win, event):
print 'Click Me'
win.Close()
Mixin.setMixin('mainframe', 'OnClick', OnClick)

setPlugin是Plugin设置方法,它将把init与槽类('mainframe')的某个调用点相关联,由槽类的实例进行调用。而setMixin是Mixin 设置方法,它将把OnClick插入到槽类中,成为槽类的一个成员函数。

同时我们还需要修改MainFrame,增加一个调用点:

import Mixin
import wx

class MainFrame(wx.Frame, Mixin):
__mixinname__ = 'mainframe'

def __init__(self, parent, title='Test'):
self.initmixin()
wx.Frame.__init__(self, parent, -1, title=title)
self.callplugin('init', self)

这样,槽类与Mixin文件都准备好了。如何才能将它们真正关联起来呢?很简单:在启动程序中将Mixin文件作为一个模块导入即可。这样真 正的关联会等到运行时,首先通过导入先将所有Plugin和Mixin搜集起来,然后再等到创建实现时,通过self.initmixin()方法真正实现 关联。并且这种操作只会执行一次。

因此Mixin与Plugin的区别就是:Mixin实现类的新方法和属性,而Plugin实现调用点的具体处理。更简单地理解:Mixin是对未知的扩展,而 Plugin是对已知的扩展。

[@more@]

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/764121/viewspace-907703/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: EmEditor 优点
请登录后发表评论 登录
全部评论
  • 博文量
    32
  • 访问量
    1431413