如何正确设计许多sub-classes的组合?

How to propely design a combination of many sub-classes?

我有一个parentclass - Product

public abstract class Product {}

和扩展它的 3 sub-classes:

  1. public class Vinyl extends Product {}

  2. public class Book extends Product {}

  3. public class Video extends Product {}

所有 sub-classes 使用其特定实现覆盖 preview() 方法。 现在,我有一个新的设计需求:我需要定义一个 combo item of vinyl & book 其中还有一个 preview() 方法(是黑胶唱片和书籍的组合)。在说明中它说我可以创建 Interface\ class 字段成员或我想支持它的任何实现,但我不确定具体如何。

新设计是否也应该与 inheritance 一起实施,还是我应该更改当前设计?

Is the new design should also be implemented with inheritance or should I change the current design?

新的设计完全可以通过继承来实现。但是真正的问题是你会有太多的子类。您可以轻松地创建一个名为 VinylBookProduct 的新子类并完成它。但是当你必须引入另一个组合时会发生什么,比如 VinylVideo。您还必须为此创建一个新的子类等等。

解决办法是结合使用继承和组合。 Composite 模式非常适合这个问题。根据维基百科:

The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.

让我们先定义一个CompositeProduct

public class CompositeProduct` extends Product {
     private List<Product> products;

     public CompositeProduct(List<Product> products) { this.products = products }

     public String preview() {
          String previewText = "";
          for(Product product : products) { previewText+=product.preview(); }
          return preview;

     }
}

您现在拥有了一个复合产品,它的行为就像是一个单一的产品,让您可以即时创建组合产品,而无需为每个组合创建新的子类。

如何即时创建产品的示例:

Book book = new Book();
Vinyl vinyl = new Vinyl();
List<Product> products = new List<>();
products.add(book);
products.add(vinyl);
CompositeProduct vinylBook = new CompositeProduct(products);

如果您正在考虑为您的产品动态添加额外的行为,您还可以看看 Decorator 模式。

我想提供一个替代方案,因为我对另一个解决方案不满意。(不要误会我的意思,它简单直接,而且 Composite 概念是一个非常好的学习概念,并且用户还提到装饰器模式,它真的很有用。

我对该解决方案的问题是你提供了产品(无论它们是什么)然后你能做什么?

让我们想象一下

public abstract class Product {
    abstract void preview();
}

现在你的 CompositeProduct 太通用了,只能实现这样的东西

void preview(){
    for(Product product : products) product.preview();
}

我敢打赌这不是你想要的。

我的替代方法是通过接口使用组合。关于域的更多细节,我不能说太多,所以我将举一个简单的例子。

什么是书?让我们想象一些可读的东西。

public interface Readable { void read(); }

public class Book extends Product implements Readable {}

什么是乙烯基?可显示

public interface Showable { void show(); }

public class Vinyl extends Product implements Showable {}

现在 BookVinyl 将只是

public class BookVinyl extends Product implements Readable, Showable { }

这会给你带来什么?那么,现在 BookVinyl 可以像书一样阅读,也可以像 Vinyl 一样展示。预览呢?它可以显示然后阅读或其他任何东西。