我已经使用 Java 很长时间了,但我从来没有发现,是什么让它factories
如此特别。有人可以向我解释一下吗?我有什么理由要实现自己的factory
(如果可能的话)?
6 回答
工厂模式非常适合解耦类。例如,让我们假设一个通用接口Animal
和一些实现它的类。Dog
, Cat
.
如果你不知道用户在运行时想要生成什么,那么你就不能创建一个Dog
指针。它根本行不通!
但是,您可以做的是将其移植到单独的类,并在运行时将鉴别器传递给工厂类。然后该类将返回该对象。例如:
public Animal getInstance(String discriminator)
{
if(discriminator.equals("Dog")) {
return new Dog();
}
// etc.
}
调用类简单地使用:
String type = "Dog";
Animal value = Factory.getInstance(type);
这使得代码具有极强的可读性,将决策逻辑与对值执行的逻辑分开,并通过一些通用接口将类解耦。总而言之,很漂亮的图案!
IMO 工厂类的最大好处是配置和数据封装。API 设计可能是此类类派上用场的最常见场景。
例如,通过为开发人员提供工厂类而不是直接访问,我有一种方法可以轻松防止有人弄乱我的 API 内部。通过工厂课程,我还可以控制您对我的基础架构的了解程度。如果我不想告诉你关于我如何在内部提供服务的一切,我会给你一个工厂类。
出于可靠性和统一设计目的,最关键的内部结构应该包含在工厂类中。
它们是一种确保随机出现的开发人员不会:
- 打破内部结构
- 获得不需要的特权
- 中断配置格式
另一个很好的例子如下。假设用户想使用一些集合来执行操作(在这种情况下选择集合来创建倒排索引)。您可以创建如下界面:
interface CollectionsFactory {
<E> Set<E> newSet();
<K, V> Map<K, V> newMap();
}
然后你可以创建一个以集合工厂为参数的类。
public class ConcreteInvertedIndex implements InvertedIndex {
private final Map<String, Set<Document>> index;
private final Set<Document> emptyDocSet;
private final CollectionsFactory c;
public ConcreteInvertedIndex(CollectionsFactory c){
this.c = c;
this.index = c.newMap();
this.emptyDocSet = c.newSet();
}
//some methods
}
最后由用户决定他想使用哪些集合来执行这些操作:
CollectionsFactory c = new CollectionsFactory() {
@Override
public <E> Set<E> newSet() {
return new HashSet<E>(); //or you can return a TreeSet per example
}
@Override
public <K, V> Map<K, V> newMap() {
return new TreeMap<K, V>();//or you can return an HashMap per example
}
};
InvertedIndex ii = new ConcreteInvertedIndex(c);
使用工厂方法模式
· 一个类不能预测它必须创建的对象类。
· 一个类希望它的子类指定它创建的对象。
· 类将责任委托给几个助手子类之一,并且您希望本地化有关哪个助手子类是委托的知识。
工厂在 JDK 中广泛使用以支持 SPI(服务提供者接口)的概念 - 旨在由第三方实现或扩展的 API。例如 DocumentBuilderFactory.newInstance() 使用复杂的 4 步搜索算法来查找实际实现。
我认为不是开发库而是开发应用程序的程序员应该在软件设计中支持“简单就是最好”的方法。
您可以将它们与私有构造函数结合使用来创建单例。它确保 bean(可能是服务)不能被创建为非单例。
您还可以通过将其设为私有来禁止使用构造函数创建类,这样您就可以在工厂方法中添加一些逻辑并且没有人可以绕过它。
编辑:我知道一个人会用带参数的“创建”方法替换每个 bean 中的构造函数(以便集中 bean 填充逻辑),但我不是这种方法的忠实粉丝。