我对抽象工厂模式感到好奇。从Java 8我们有默认方法,它是否意味着我们可以将抽象类替换为接口?当我们需要非静态/最终字段时,我可以看到一个缺点。我们做不到界面。当老式工厂有更多的优势时,你能给我一些例子(除了我列出的那个)吗?
答案 0 :(得分:3)
技术上你可以,但你不应该。
接口上的默认实现是一个具有一些非常特定目的的工具 - 主要是为了向一个非常可能由您的控件之外的客户端实现的接口添加功能,或者用于重复实现的接口,其中默认实现将是繁重的重新实现。
当你从一些普通的父母行为中延伸时,他们不意图作为抽象类的替代(甚至是补充)。
现在,那就是说,抽象工厂模式与Java使用abstract关键字几乎没有关系。抽象工厂模式是关于隐藏(或抽象)给定客户端实际用于生成对象的具体工厂实现。工厂的工厂方法被定义为返回的可能是具体类,抽象类或接口。
所以,例如 -
假设你有一些班级,GuiPainter。它有一个方法#paintWindow。
在幕后,您已经介绍了一个Window,其中包含Apple特定的实现,如AppleWindow,AndroidWindow,UbunutuWindow(等)。每个Window实现在需要构建的方式上都有所不同。
一种方法是使用AppleWindowFactory,AndroidWindowFactory,UbuntuWindowFactory(等)构建GuiPainter,以及查找操作系统并决定使用哪个工厂的方法。但是,所有GuiPainter真正想要的是Window的任何实例 - 它没有其他特定于操作系统的知识。
因此,我们引入一个WindowFactory,它返回一个Window。 WindowFactory是一个工厂,具有发现操作系统的知识,并决定使用哪个具体的Window工厂 - 从GuiPainter中抽象出这个责任。
Window本身可能是一个具有单一实现的具体类,只是基于OS的配置差异。它可能是一个具有特定于操作系统的实现的抽象类(如AppleWindow,AndroidWindow等)。它甚至可能是由工厂匿名实现的接口。什么窗口 并没有改变客户端不再需要担心操作系统特定的废话来获得它想要的窗口。
这有意义吗?
答案 1 :(得分: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
描述非常好。
您正在谈论default
和factory
方法,但它们确实彼此不同,我觉得您正在混合一些东西。
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>
及其子类。