抽象工厂模式实现为接口

问题描述 投票:1回答:2

我对抽象工厂模式很好奇。从Java 8我们有默认方法,它是否意味着我们可以将抽象类替换为接口?当我们需要非静态/最终字段时,我可以看到一个缺点。我们做不到界面。当老式工厂有更多的优势时,你能给我一些例子(除了我列出的那个)吗?

java design-patterns interface factory
2个回答
3
投票

你在技术上可以,但你不应该。

接口上的默认实现是一个具有一些非常特定目的的工具 - 主要用于向控件之外的客户端实现非常可能实现的接口添加功能,或者用于重复实现的接口,默认情况下实施将是繁重的重新实施。

当您从一些普通父母的行为延伸时,它们不是用于抽象类的替代(或甚至补充)。

现在,也就是说,抽象工厂模式与Java使用abstract关键字几乎没有关系。抽象工厂模式是关于隐藏(或抽象)给定客户端实际用于生成对象的具体工厂实现。工厂的工厂方法定义为返回的内容可以是具体类,抽象类或接口。

所以,例如 -

假设你有一些班级,GuiPainter。它有一个方法#paintWindow。

在幕后,您已经介绍了一个Window,具有特定于操作系统的实现,如AppleWindow,AndroidWindow,UbunutuWindow(等)。每个Window实现在需要构建的方式上有所不同。

一种方法是使用AppleWindowFactory,AndroidWindowFactory,UbuntuWindowFactory(等)构建GuiPainter,以及找到操作系统并决定使用哪个工厂的方法。但是,所有GuiPainter真正想要的是Window的任何实例 - 它没有其他特定于操作系统的知识。

因此,我们引入一个Wi​​ndowFactory,它返回一个Window。 WindowFactory是一个工厂,具有发现操作系统的知识,并决定使用哪个具体的Window工厂 - 从GuiPainter中抽象出这个责任。

窗口本身可能是具有单个实现的具体类,并且仅基于OS的配置差异。它可能是一个具有特定于操作系统的实现的抽象类(如AppleWindow,AndroidWindow等)。它甚至可能是由工厂匿名实现的接口。什么窗口不会改变,客户端不再需要担心操作系统特定的废话来获得它想要的窗口。

那有意义吗?


0
投票

是的,这是一种广泛使用的技术。

你经常偶然发现公共interfaces,例如:

public interface Cache<K, V> {
    public Optional<V> get(K k);
    public V put(K k, V v);
    // ...
}

和隐藏(= package-private或嵌套的private)实现。

class SoftCache<K, V> implements Cache<K, V> {
    private final Map<K, SoftReference<V> dataMap;
    // ...
}
class WeakCache<K, V> implements Cache<K, V> {
    private final Map<K, WeakReference<V> dataMap;
    // ...
}

不需要多个实现,即使只有一个子类,该模式也是有效的并且完全适用。


使用缓存系统的类不关心实现细节。他们只关心暴露的行为,这可以通过interface很好地描述。

你在谈论defaultfactory方法,但它们确实彼此不同,我觉得你正在混合一些东西。

default方法were mostly added因为如果你有20个类实现MyInterface并且在你的界面中添加了一个方法,那么在20个不同的地方实现一个行为(在所有类中通常是相同的)是一件非常痛苦的工作。

我觉得Java 8/9+正在大力推行这种模式:interfaces内的工厂方法。以API Set.of(...)Map.of(...)等为例。

java.util.Stream<T>为例。

您通常以这种方式使用它(对象):

private Stream<Element> stream;

要么

private IntStream intStream;

你不关心你当前拥有的元素是Head元素,OfRef或其他任何东西。

这些是隐藏的详细信息,无法从您的代码中访问。

然而,interface Stream<T>确实暴露了工厂方法of(以及其他):

/**
 * Returns a sequential {@code Stream} containing a single element.
 *
 * @param t the single element
 * @param <T> the type of stream elements
 * @return a singleton sequential stream
 */
public static<T> Stream<T> of(T t) {
    return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

让你的interface暴露工厂方法而不是abstract类是没有错的,但在一天结束时它完全取决于你以及你如何感觉更舒服。

还需要注意的是,java通常使用这种模式:

interface > abstract class > other classes

另请参见java.util.Collection<E>及其子类。

© www.soinside.com 2019 - 2024. All rights reserved.