抽象工厂和工厂方法模式都是创建设计模式,它解决了不同场景下的对象创建问题。
根据GOF 工厂方法模式
定义用于创建对象的接口,但让子类决定实例化哪个类。 Factory方法允许类将实例化延迟到子类。
我的理解: 客户端的动机是获取基本工厂类中的方法得到执行,这取决于现在不知道具体类的对象(在这种情况下,在向客户提供软件期间) ,它将被定义,或者它将是客户自己编写的具体实现,最有可能是框架)。未知(或可能更改)的产品提供了一种抽象类型:IProduct,并设置了一个合同,以后,任何产品实现都必须实现此接口。
IProduct界面
package com.companyx;
public interface IProduct {
public void serve();
}
使用'方法'需要执行
package com.companyx;
public abstract class Factory {
public abstract IProduct createProduct();
private void performCriticalJob(){
IProduct product = createProduct();
product.serve();
}
public void executeJob(){
//some code
performCriticalJob();
//some more code
}
}
一些具体产品
package com.companyx;
class AppAProductFeatureX implements IProduct{
@Override
public void serve() {
//some code
}
}
具体产品的工厂
package com.companyx;
public class AppAFeatureXProductFactory extends Factory{
@Override
public IProduct createProduct() {
return new AppAProductFeatureX();
}
}
客户代码
package com.clientcompany;
import com.companyx.AppAFeatureXProductFactory;
import com.companyx.Factory;
public class Client {
public static void main(String[] args) {
Factory fact = new AppAFeatureXProductFactory();
fact.executeJob();
}
}
根据GOF 抽象工厂模式
提供用于创建相关或从属对象族的接口,而无需指定其具体类。
我的理解 客户对产品感兴趣,此模式通过隐藏工厂类后面的具体产品类来帮助提供产品。
客户需要的产品类型
package com.companyb;
public interface IProductA {
public void performAJob();
}
产品的实施
package com.companyb;
//can be named better, but lets go with this name for this time
public class ProductAVersion1 implements IProductA{
@Override
public void performAJob() {
// some code
}
}
工厂界面,(它也可以是抽象类)
package com.companyb;
public interface IFactory {
public IProductA createProduct();
}
Factory的具体实现o创建ProductA
package com.companyb;
public class FactoryA implements IFactory{
@Override
public IProductA createProduct() {
return new ProductAVersion1(); // concrete class of product is hidden
}
}
客户代码
package com.clientcompany.productprovider;
import com.companyb.IFactory;
import com.companyb.IProductA;
public class SomeClientClass {
private IFactory factory;
private IProductA product;
public void doSomeJobWithProductA() {
// some code
product.performAJob();
//someCode();
}
public void setFactory(IFactory factory) {
this.factory = factory;
this.product = factory.createProduct();
}
}
package com.clientcompany.productprovider;
import com.companyb.FactoryA;
public class SomeOtherClientCode {
public static void main(String[] args) {
SomeClientClass someClientClass = new SomeClientClass();
someClientClass.setFactory(new FactoryA());
someClientClass.doSomeJobWithProductA();
}
}
Q1 :抽象工厂模式中是否需要相关产品系列,如果只有一种产品(如上所述)有各种子类型,那么这种模式仍然是相关的但不是各种相关类型?
Q2 我的理解是否正确?
Q3 上面给我带来了另一个疑问:Factory方法更适合框架(客户端可以提供产品的实现),就像模板方法模式一样,工厂调用{{1}具体实现从用户提供的Concrete Factory实现? 同样,抽象工厂更适合图书馆开发,具体的产品类别(可能会有所不同)隐藏在更稳定的工厂类别背后?
答案 0 :(得分:1)
根据我的理解:
A1 :产品系列不一定必须相关,如example diagram所示,只需要了解产品类型的客户。这种关系大多是自然的,因为你可能不希望同一个客户创建2个不相关的对象,例如,如果你有一个" AbstractPizzaFactory"它会看起来很奇怪。创造比萨饼和汽车,没有?
A2 :从技术上讲,您可以在Factory模式中提供默认的工厂方法,这样您仍然可以创建(默认)新对象,而无需始终对其进行子类化。
A3 :我同意你的观点,尽管创建图书馆或框架绝不是黑白分明。
答案 1 :(得分:1)
我很难穿上你的鞋子。但我对这个问题很感兴趣,所以我会试一试。这里涉及的概念包括library
,framework
,factory method
,abstract factory
和product family
等。
首先,library vs framework
与工厂,抽象工厂或任何模式无关。图书馆与框架的争论不是从模式发挥作用的实现角度出发的。例如,JUnit是一个带有丰富断言库的框架。那么,对于内部实现,junit是否应该优先选择其他模式? Java本身是一个带有JCL库的框架。 Dot Net与java类似,甚至称自己为框架,并包含BCL库。因此,在实施环境中没有更多的框架与图书馆辩论。
所以问题归结为你应该使用哪种模式?它不是关于差异,这是明确的,而是关于在哪种场景中使用哪一个。在此上下文中,Client Code
是您正在键入的call
所有代码。一些代码是由您或其他人在相同或不同的jar中,来自相同或不同的组织编写并不重要。从一个代码片段的角度来看,任何其他代码(即使在同一个类的不同方法中)是客户端代码,如果该代码有可能call
你正在输入的代码。
在键入任何代码(无论框架或库状态)时,有时我们需要获取某些对象的实例。我们可能需要一个BufferedReader
。如果在编译时我们绝对确定对象的具体类,KISS
它并与new
一起使用。
我们可能不知道实例的具体类。现在质疑客户端代码是否有此信息?如果客户端代码知道实际的具体类,但我不知道,那么我们使用FactoryMethod
模式。我输入的代码将在(例如)其参数列表中询问工厂对象的实例。知道实际具体类的客户端代码将提供将进行创建的工厂对象。在JDBC
中可以看到这种情况的示例,就像我们要处理sql语句一样。在编译时,我们不知道是否应该实例化mysql.JDBC4PreparedStatement
或microsoft.SQLServerStatement
。它取决于连接字符串,这取决于最终用户。因此,我们抓住Connection
个实例并将其提交给createStatement()
。请参阅,我们将sql.Statement
类型的对象的构造委托给sql.Connection
的子类。这里conn
实例是工厂对象。我们如何掌握工厂是无关紧要的,只是我们从客户代码获得它。
如果我们需要一个Process
对象的实例,并且在编译时我们不知道它是Win32Process
还是UnixProcess
,我们将其创建的责任委托给与工厂模式相关的ProcessBuilder
builder pattern
。同样适用于jdbc ConnectionManager
。
如果有很多不同的类通过继承而不是家庭相关,我们可能会使用AbstractFactory
。例如,取jdbc的点网对应DbProviderFactory
。我的代码需要Connection
,Command
,DataReader
等实例,这些实例与继承无关,而是与MySql或SqlServer的 family 相关。所以我们得到了DbProviderFactory
的子类的实例。可能是MySqlProviderFactory
或SqlProviderFactory
取决于运行时和客户端代码。一旦我们拥有该工厂,我们就可以CreateCommand()
,CreateConnection()
等。
希望这有助于您在工厂模式和抽象工厂模式之间进行选择。
答案 2 :(得分:0)
抽象工厂可以看作是工厂方法的集合。
为了更好地理解现实生活中的例子,可以提供帮助:
Factory Method - 橡皮泥/模具
Abstract Factory - 卡片工厂