0

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

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

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

有些事情对我来说不是很清楚,例如,仅仅引用另一个模块会破坏我系统的模块化?

假设我有一个数据库访问模块,它可以选择使用缓存模块来存储复杂查询的结果。正如任何人所看到的,我至少会对缓存模块有一个命名依赖项。

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

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

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

为了澄清一点,这里有一个例子(在 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 可接受的问题。

PS:英语不是我的母语,可能有些部分会有点混乱

4

3 回答 3

1

仅仅引用另一个模块会破坏我系统的模块化吗?

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

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

另一个工具——设计只有单一职责的模块(及其接口)。这也使它们更加细化、独立和可维护。

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

于 2013-05-20T12:14:08.660 回答
1

一些资源(不是理论上的):

于 2013-05-20T00:22:17.320 回答
1

我想出了一个替代方案,就像单独创建每个组件一样,甚至不知道其他组件的存在不是其运行所必需的

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

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

因此,对于内部模块化设计,我选择了基于接口的 N 层架构。基本上,架构依赖于这些层:

  1. 域/实体
  2. 接口 [取决于 1]
  3. 服务 [取决于 1 和 2]
  4. 存储库/DAL [取决于 1 和 2]
  5. 表示层 [取决于 1,2,3,4]

不幸的是,我认为这在 php 项目中不能很好地实现,因为它需要在每一层中单独的项目/dll 引用。但是,遵循架构可以帮助模块化应用程序。

对于每个模块,我们都需要做基于接口的设计。它有助于增强代码的模块化,因为您可以稍后更改实现,但仍保持使用者不变。

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

最后但同样重要的是,如果你想让你的应用程序模块化到 UI,你可以做Service Oriented Architecture. 这只是让你的应用程序成为一堆服务,然后让 UI 来使用服务。这种设计有助于将你的 UI 与你的逻辑分开。您以后可以使用不同的 UI,例如桌面应用程序,但仍使用相同的逻辑。不幸的是,我没有任何可靠的 SOA 来源。

编辑:

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

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

我对 Zend 了解不多,但是我猜 Zend 中的模块化意味着它可以在不改变框架内部的核心(替换代码)的情况下进行扩展。

如果你这么说:

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

然后它不是模块化的。它是集成的,意味着您的数据库访问模块在没有缓存的情况下将无法工作。在引用 C# 组件时,它选择提供List<T>BindingList<T>提供不同的功能。在您的情况下,恕我直言,最好提供CachedDataAccessand DataAccess

于 2013-05-20T04:58:08.777 回答