类的结构设计方法

The way to design structure of classes

我的 classes 结构非常简单。 Class B和C继承自A。在某些功能和属性的情况下,功能相似。 Class B 和 C 对数据的处理不同,但 classes 具有相同的输出(创建输出的函数在 A class 内部)。结构示例:

现在我需要扩展功能。我需要添加选项以在处理和数据输出方面存在一些差异 (class X)。此选项由配置文件管理,因此我想保留下载、处理和输出数据的旧方式,例如:

  1. 选项 1 - 使用 旧方法处理和输出 在没有 线程 的情况下下载数据
  2. 选项 2 - 使用新的处理和输出方式下载没有线程的数据
  3. 选项 3 - 使用 threads 下载数据,使用 old 方式处理和输出
  4. 选项 4 - 使用新方式处理和输出无需线程下载数据

我不确定如何实现新处理和输出数据的组合。我需要 Class B 和 X (BX) 以及 Class C 和 X (CX) 的组合。我考虑了这些选项:

  1. 最简单但最糟糕的方法 - 在 class B 和 class A 中复制一些函数。
  2. 保留 classes A 和 B 并添加 BX 和 AX classes 的组合。
  3. 重写classes A和B只为下载数据。然后添加classes用于处理数据,然后添加classes用于输出数据。所有 classes 将共享对象。看起来是最好的选择,但需要做的工作最多。

有没有更好的选择(例如设计模式或类似的东西)如何以最干净的方式扩展 classes?

在我看来你有一个Dataflow

你拥有的是获取(下载)数据 -> 处理数据 -> 输出数据.这基本上是一个具有三个阶段的管道。

如果您使用对象来为您建模,则有两种类型的对象:执行操作的对象和一种或多种管理数据流和操作顺序的对象。

让我们使用三个接口(您可以使用抽象 classes 来定义它们并不重要)来定义管道的步骤:IDataDownloader, IDataProcessorIDataOutputer.

让我们添加另一个对象来表示和管理管道:

(注意:我没有python的经验,所以我会用C#写它抱歉..)

public class Pipeline {

  private IDataDownloader mDataDownloader;
  private IDataProcessor mDataProcessor;
  private IDataOutputer mDataOutputer;

  public void Setup() {

    // use a config file to select between the two ways

    if (Config.UseOldWayDownloader) {
      mDataDownloader = new OldWayDownloader();
    }
    else {
      mDataDownloader = new NewWayDownloader();
    }
    // ....

    // or you can use service locator or dependecy injection that will get
    // a specific downloader based on configuration/setup

    mDataDownloader = Services.Get<IDataDownloader>();
    // ....
  }

  public void Execute() {

    var data = mDownloader.Download();

    var processedData = mDataProcessor.Process(data);

    mDataOutputer.Output(processedData);
  }
}

这样你会变得很好 separation of concerns 并且你会得到一个可以扩展的模块化系统。该系统也是可组合的。您可以用不同的方式组合它的各个部分。

看起来工作量更大,但事实并非如此。干净的设计通常更容易编写和扩展。

的确,您可能会多写一些代码,但是由于设计简洁,您可以更快地编写此代码,并且可以节省调试时间。调试是我们编写软件的大部分时间,但它经常被程序员忽视,认为他们只能通过编写和代码行来衡量。

松散类型语言就是一个例子。很多时候你写的代码越少越胖,但是很容易因为错误而出错。万一出错,你会得到更多(有时更难)调试,这样你就浪费了时间。

如果您从一个简单的概念验证应用开始,它们将显着加快开发速度。一旦您达到了拥有经过测试的强大软件的地步,就会有不同的力量介入。

为了确保您的软件健壮,您必须编写更多测试和更多 checks/assertions 以确保一切 运行 顺利进行。所以最后你可能会有相同数量的代码,因为强类型会为你做一些检查,你可以写更少的测试。

那什么更好呢?嗯...这取决于。

有几个因素会影响开发速度。这 程序员对一门语言的品味和经验。该应用程序也会对此产生影响。有些应用程序更容易用松散类型的语言编写,而另一些则更容易用强类型语言编写。

速度可以不同,但​​并不总是这样,有时只是一样。

我认为,在您的情况下,您会浪费更多时间来尝试获得正确的层次结构并对其进行调试,即使最后您的代码少了几行。在较长的 运行 中,如果您需要扩展它,拥有一个更难理解的设计会大大降低您的速度。

在管道方法中添加新的下载、处理或输出数据的方法就是添加单个 class。

好吧,为了让它成为 UML 答案,我添加了 class 图:

Pipeline 提到了这三个处理 classes。它们都是抽象的,因此您需要以不同的方式实现它们。 configuration 将根据配置(文件)的内容分配它们。