如何按照功能设计模块包?

下图是一个高耦合、低相干性的两个包调用设计:

┌──────────────────────────────────┐     ┌──────────────────────────────┐
│  pl.koziolekweb.app.controllers  │     │  pl.koziolekweb.app.services │
│                                  │     │                              │
│             ┌────┐               │     │             ┌────┐           │
│     ┌───────► C1 ├───────────────┼─────┼──┬──────────► S1 │           │
│     │       └─┬──┘               │     │  │          └────┘           │
│     │         │                  │     │  ▼                           │
│     │       ┌─▼──┐               │     │  │          ┌────┐           │
│     ├───────► C2 ├───────────────┼─────┼──┴──────────► S2 │           │
│     │       └────┘               │     │             └────┘           │
│     │                            │     │                              │
│     │       ┌────┐               │     │             ┌────┐           │
│     ├───────► C3 ├───────────────┼─────┼─────────────► S3 │           │
│     │       └────┘               │     │             └─┬──┘           │
│     │                            │     │               │              │
│     │                            │     └───────────────┼──────────────┘
│  ┌──┴────┐                       │                     │
│  │       │                       │                     │
│  │ Utils ◄───────────────────────┼─────────────────────┘
│  │       │                       │
│  └───────┘                       │
│                                  │
└──────────────────────────────────┘

控制器包controllers与服务包services之间有多个连接。
其中一些是双向的,即服务使用来自控制器的元素。

在这样的系统中,我们唯一能做的就是尝试将类扔到Utils一个单独的包中来消除这种循环依赖。然而,我们并没有解决主要问题,即包之间的多重交互。

让我们尝试一种不同的方法。让我们按“业务”功能对类进行分组:

┌───────────────────────┐  ┌───────────────────────┐
│pl.koziolekweb.app.f1  │  │pl.koziolekweb.app.f2  │
│                       │  │                       │
│ ┌────┐     ┌────┐     │  │ ┌────┐                │
│ │    ├─────►    │     │  │ │    │                │
│ │ C1 ├──┼──┐ C2 │     │  │ │ C3 ├────┐           │
│ │    │  │  │    │     │  │ │    │    │           │
│ └─┬──┤  │  ├─┬──┘     │  │ └─┬──┘    │           │
│   │──┼──┼──┼─│        │  │   │       │           │
│ ┌─▼──┤  │  ├─▼──┐     │  │ ┌─▼──┐    │           │
│ │    │  │  │    │     │  │ │    │    │           │
│ │ S1 │  │  │ S2 │     │ ┌┼─┤ S3 │    │           │
│ │    │  │  │    │     │ ││ │    │    │           │
│ └────┘  │  └────┘     │ ││ └──┬─┘    │           │
│         │             │ ││    │      │           │
│ ┌───────▼──────┐      │ ││ ┌──▼──────▼────┐      │
│ │              │      │ ││ │              │      │
│ │ InternalUtils│      │ ││ │ InternalUtils│      │
│ │              │      │ ││ │              │      │
│ └────┬─────────┘      │ ││ └──────────────┘      │
│      │                │ ││                       │
└──────┼────────────────┘ │└───────────────────────┘
       │               ┌──┘
       │               │
    ┌──┼───────────────┼──────────┐
    │pl│koziolekweb.app│utils     │
    │  │               │          │
    │ ┌▼────────┐ ┌────▼───────┐  │
    │ │IntUtils │◄│StringUtils │  │
    │ └─────────┘ └────────────┘  │
    │                             │
    └─────────────────────────────┘

现在你或多或少可以看到正在发生的事情:
  • 包是连贯的,即它们内部发生大量交互,同时它们不会与其他包过度耦合。
  • 确实,这个包pl.koziolekweb.app.f1非常“混乱”,但我们将这种混乱限制在一个地方。
  • 使用这个包会很容易,因为我们已经隔离了问题。我们可以自由地更改它,并且潜在的代码合并不会导致冲突。