模块化设计和模块间参考

时间:2013-05-19 23:48:26

标签: oop design-patterns

我不太确定这个标题是否适合我要提出的这个问题。

我打算创建一个网络MVC框架作为我的毕业论文,并在之前与我的顾问谈话中试图定义一些成就,他说服我在这个项目中应该选择模块化设计。

我已经开发了一些东西然后停下来一段时间来分析它会有多少模块化而且我不能真正做到这一点,因为我不知道“模块化”的真正含义。

有些事情对我来说不是很谨慎,例如,只是引用另一个模块会破坏我系统的模块性?

假设我有一个数据库访问模块,OPTIONALY可以使用Cache模块存储复杂查询的结果。任何人都可以看到,我至少会对缓存模块有一个命名依赖。

在我的“模块化设计”概念中,我可以单独分发每个组件,并使其与其他人开发的其他组件进行交互。在这种情况下,我表示,如果有人想使用我的数据库访问模块,他们也必须使用缓存,即使他不会使用它,仅用于引用/命名目的。

所以,我想知道这是否真的是模块化设计。

我想出了一个替代方案,就像单独创建每个组件一样,甚至不知道其功能不是绝对必需的其他组件的存在。为了扩展功能,我可以基于装饰器和适配器创建一些结构。

为了澄清一点,这里是一个例子(在PHP中):

之前

interface Cache {
    public function isValid();
    public function setValue();
    public function getValue();
}

interface CacheManager {
    public function get($name);
    public function put($name, $value);
}

// Some concrete implementations...

interface DbAccessInterface {
    public doComplexOperation();
}

class DbAccess implements DbAccessInterface {
    private $cacheManager;

    public function __construct(..., CacheManager $cacheManager = null) {
        // ...
        $this->cacheManager = $cacheManager;
    }

    public function doComplexOperation() {
        if ($this->cacheManager !== null) {
            // return from cache if valid
        } 
        // complex operation
    }
}

之后

interface Cache {
    public function isValid();
    public function setValue();
    public function getValue();
}

interface CacheManager {
    public function get($name);
    public function put($name, $value);
}

// Some concrete implementations...

interface DbAccessInterface {
    public function doComplexOperation();
}

class DbAccess implements DbAccessInterface {
    public function __construct(...) {
        // ...
    }

    public function doComplexQuery() {
        // complex operation
    }
}

// And now the integration module

class CachedDbAcess implements DbAccessInterface {
    private $dbAccess;
    private $cacheManager;

    public function __construct(DbAccessInterface $dbAccess, CacheManager $cacheManager) {
        $this->dbAccess = $dbAccess;
        $this->cacheManager = $cacheManager;
    }

    public function doComplexOperation() {
        $cache = $this->cacheManager->get("Foo")
        if($cache->isValid()) {
            return $cache->getValue();
        }
        // Do complex operation...
    }
}

现在我的问题是: 这是最好的解决方案吗?我应该为没有要求的所有模块一起工作,但这样做会更有效率吗?

任何人都会以不同的方式做到这一点吗?

我还有一些涉及此问题的更多问题,但我不知道这是否是stackoverflow的可接受问题。

P.S。:英语不是我的第一语言,也许某些部分可能会有点混乱

3 个答案:

答案 0 :(得分:1)

一些资源(非理论):

答案 1 :(得分:1)

  
    

我提出了一个替代方案,就像单独创建每个组件一样,甚至不知道其功能不是绝对需要的其他组件的存在

  

如果你自己提出这个想法,那就太好了。声明本身是模块化编程的关键。

插件架构在可扩展性方面是最好的,但是在内部应用程序中尤其难以维护。根据插件架构的复杂性,它可以通过添加插件逻辑等使您的代码更加复杂。

因此,对于帧内模块化设计,我选择N层,基于接口的架构。基本上,架构在这些层上传递:

  1. 域/实体
  2. 界面[取决于1]
  3. 服务[取决于1和2]
  4. 存储库/ DAL [取决于1和2]
  5. 表示层[取决于1,2,3,4]
  6. 不幸的是,我不认为这在php项目中是可以实现的,因为它需要在每个层中分离项目/ dll引用。但是,遵循该体系结构可以帮助模块化应用程序。

    对于每个模块,我们需要进行基于接口的设计。它可以帮助增强代码的模块性,因为您可以稍后更改实现,但仍然保持消费者的相同。

    在这个stackoverflow问题中,我提供了与此基于界面的设计类似的答案。

    最后但并非最不重要的是,如果您希望将应用程序模块化到UI,则可以执行Service Oriented Architecture。这只是使您的应用程序成为一堆服务,然后使UI使用该服务。此设计有助于将UI与逻辑分离。您可以稍后使用不同的UI,例如桌面应用程序,但仍然使用相同的逻辑。不幸的是,我没有任何可靠的SOA来源。

    编辑:

    我误解了这个问题。这是我对模块化框架的看法。不幸的是,我对Zend知之甚少,所以我将在C#中给出例子:

    • 它由模块组成,从最小模块到较大模块。 C#中的示例是您可以在应用程序中使用Windows Form(更大),还可以使用Graphic(较小)类在屏幕上绘制自定义形状。
    • 在不更改基类的情况下,它是可扩展的或可替换的。在C#中,您可以将FormLoad事件(可扩展)分配给Form类,继承FormList类(可扩展)或覆盖表单draw方法以创建自定义窗口图形(可替换)
    • (可选)易于使用。在正常的DI接口设计中,我们通常将较小的模块注入较大的(高级)模块。这将需要一个IOC容器。有关详细信息,请参阅我的question
    • 易于配置,不涉及任何神奇的逻辑,例如Service Locator Pattern。在Google中搜索Service Locator is an Anti Pattern

    我对Zend知之甚少,但我想Zend中的模块化意味着它可以在不改变框架内核心(替换代码)的情况下进行扩展。

    如果你这么说:

      
        

    如果有人想使用我的数据库访问模块,他们也必须使用缓存,即使他不会使用它,仅用于引用/命名目的。

      

    然后它不是模块化的。它是集成的,意味着没有Cache,您的数据库访问模块将无法工作。在参考C#组件时,它选择提供List<T>BindingList<T>来提供不同的功能。在您的情况下,最好提供CachedDataAccessDataAccess

答案 2 :(得分:1)

  

只是引用另一个模块会破坏我系统的模块性?

不一定。这是一种依赖。拥有依赖是完全正常的。没有依赖关系模块不能相互交互(除非你间接进行这种交互,这通常是一种不好的做法,因为它隐藏了依赖关系并使代码复杂化)。模块化设计意味着管理依赖关系,而不是删除它们。

一个工具 - 正在使用接口。通过接口引用模块产生所谓的软依赖。这样的模块可以接受任何接口的实现作为依赖,因此它更加独立,因此更易于维护。

另一个工具 - 设计只具有单一响应性的模块(及其接口)。这也使它们更加细化,独立和可维护。

但有一条线你不应该交叉 - 盲目地应用这些工具可能会导致过于模块化和过于通用的设计。使事情过于细化会使整个系统变得更加复杂。您不应该解决所有开发人员都可以使用的泛型问题,制作通用模块(除非这是您的目标)。首先,您的系统应该解决您的域任务并使其足够通用,但不能超过它。