简单工厂和工厂方法设计模式的区别
Simple factory and Factory Method Design pattern difference
我正在学习新的设计模式,并且我正在尝试了解简单工厂模式和工厂方法模式之间的区别。首先,我想澄清一下,我尝试从 Stack-overflow 和其他网站阅读很多关于相同内容的文章,但这对我没有帮助。
这是我的问题:
让我们考虑一下我有一个产品层次结构,如下所示:
我写了一个简单的工厂class如下图
public class SimpleItemFactory {
static Item getItem(String type) {
if(type.equals("Cake")) {
return new Cake();
}else if(type.equals("Chocolate")) {
return new Chocolate();
}else {
return null;
}
}
}
所以现在我在一个地方创建了所有对象,所以如果明天发生任何更改[就像构造函数需要一个参数],我们只需要在一个地方进行更改。但它打破了 OPEN CLOSED 原则,就好像明天我们添加更多项目,如果有条件,我们需要更改 getItem() 方法。所以我们选择工厂方法模式
我们创建工厂class如下图:
public abstract class ItemFactory {
abstract Item getItem();
}
class CakeFactory extends ItemFactory {
@Override
Item getItem() {
return new Cake();
}
}
class ChocolateFactory extends ItemFactory {
@Override
Item getItem() {
return new Chocolate();
}
}
class Client{
public static void main(String[] args) {
Item chocolate = new ChocolateFactory().getItem();
System.out.println(chocolate);
}
}
现在,当客户端想要添加名为 IceCream 的新项目时,他们只需创建名为 IceCreamFactory 的新工厂并从中创建 IceCream,如下所示:
class IceCreamFactory extends ItemFactory{
@Override
Item getItem() {
return new IceCream();
}
}
class Client{
public static void main(String[] args) {
Item iceCream = new IceCreamFactory().getItem();
System.out.println(iceCream);
}
}
我的理解对吗?
我们在这里满足了开闭原则,但是对于每个产品(Item)我们需要一个工厂class,这不是成为可管理的噩梦吗?
我认为在您的示例中,工厂似乎毫无用处,因为您的 Cake 和 Chocolate 构造函数不需要任何参数。
当您想构造一个具有许多参数的复杂对象以遵守 DIP(依赖倒置原则)并避免令人尴尬的耦合时,工厂很有用。
另外,你的例子好像违反了LSP(Liskov Substitution Principle)。 Cake 和 Chocolate class 没有任何共同点,作为证据,您的抽象超级 class 被命名为 Item,这是一个非常通用的名称。
对我来说,对于复杂的不常见对象,class选择一个工厂更好,并且有效地尊重OCP(开闭原则)。
您的第一个示例对于实例化 classes 很有用,它继承了相同的 superclass,但是使用您的 classes 作为参数和反射(使用 java.lang.reflect ) 来调用构造函数,而不仅仅是使用 String 求值。 (您的 IDE 无法自动完成)并且在不匹配的情况下不要 return null,抛出 IllegalArgumentException,它更正确。
像这样:
import java.lang.reflect.Constructor;
public class SimpleItemFactory {
public <T extends Item> T createItem(Class<? extends Item> itemClass) {
try {
// construct your dependencies here
// and inject them in the getConstructor
Constructor<? extends Item> constructor = itemClass.getConstructor();
return (T)constructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException();
}
}
}
并像这样使用它:
class Client {
public static void main(String[] args) {
SimpleItemFactory factory = new SimpleItemFactory();
IceCream iceCream = factory.createItem(IceCream.class);
System.out.println(iceCream);
Cake cake = factory.createItem(Cake.class);
System.out.println(cake);
Chocolate chocolate = factory.createItem(Chocolate.class);
System.out.println(chocolate);
}
}
如果您没有依赖项,则可以直接在您的抽象项 class 中将 createItem() 方法实现为静态方法。
看看这本书,这是一个很好的资源:Head First Design Patterns
OCP只是Open for extension Close for modification的原则。如果你需要打开修改你的工厂来添加一个新的class(一个新的案例在一个开关或一个if中管理),不,你的工厂不是"OCP"。
你不应该在构造函数中计算税收,构造函数应该只是......构造一个对象......你可以使用类似策略的模式来拥有许多taxCalculator并将它们注入构造函数,使用IOC(控制反转)机制,例如依赖项注入或以简单的方式使用.....工厂(这是可以接受的),但不能使用 class 中的简单静态方法。
对不起我的英语不好,我很难回答这样复杂的问题。
其实你的理解是正确的,只是你需要注意,每个设计模式都是为了解决至少一个问题,有时它可能会带来其他问题复杂性或副作用,这意味着没有完美的设计模式可以解决所有问题。
为了学习的目的,你一个一个地应用设计模式(这使得设计模式的真正力量同样是害羞或隐藏),但是在现实世界中,设计模式是混合在一起的(或者你甚至可以发明一个新的 :p) 为了创造满足您的大部分需求并接近理想的东西,您可以遇到例如 Builder 模式与 Factory 模式的混合或 Factory 模式与 Strategy 模式的混合,甚至他们三个混合在一起。 ..
对于您的情况,我建议例如使用 Factory Method Pattern 以及 Simple Factory Pattern 和 依赖注入模式 创造出完全美丽的东西,同时满足 Open closed 原则。
class ItemFactoryContainer() {
private Map<String, ItemFactory> factories = new HashMap<>();
public void register(String name, ItemFactory factory) {
factories.put(name, factory);
}
public ItemFactory getFactory(String name) {
return factories.get(name);
}
}
public class ItemFactoryTest {
public static void main(String...args) {
ItemFactoryContainer factoryContainer = new ItemFactoryContainer();
factoryContainer.register("choclate", new ChocolateFactory ());
factoryContainer.register("cake", new CakeFactory ());
factoryContainer.register("iceCream", new IceCreamFactory ());
Chocolate choclate = factoryContainer.getFactory("choclate").getItem();
Cake cake = factoryContainer.getFactory("cake").getItem();
}
}
答案(@Mouad EL Fakir 和@François LEPORCQ)是关于静态工厂的。那是你的代码的第一部分。
还有两种风格,即工厂方法和抽象工厂)
你的代码的第二部分正在使用 CakeFactory 和 ChocolateFactory,你正在尝试使用工厂方法(尽管你的命名暗示抽象工厂)。这里工厂方法getXXX()的用法是不正确的。这些模式的目的是不同的。在您的代码中,除了增加 类 的数量外,您没有取得任何成就。 (尽管 增加的 类 和 平行层次结构 被记录为与工厂相关的成本)
我最近回答过类似的问题,看看这些回答是否有帮助
我正在学习新的设计模式,并且我正在尝试了解简单工厂模式和工厂方法模式之间的区别。首先,我想澄清一下,我尝试从 Stack-overflow 和其他网站阅读很多关于相同内容的文章,但这对我没有帮助。
这是我的问题:
让我们考虑一下我有一个产品层次结构,如下所示:
我写了一个简单的工厂class如下图
public class SimpleItemFactory {
static Item getItem(String type) {
if(type.equals("Cake")) {
return new Cake();
}else if(type.equals("Chocolate")) {
return new Chocolate();
}else {
return null;
}
}
}
所以现在我在一个地方创建了所有对象,所以如果明天发生任何更改[就像构造函数需要一个参数],我们只需要在一个地方进行更改。但它打破了 OPEN CLOSED 原则,就好像明天我们添加更多项目,如果有条件,我们需要更改 getItem() 方法。所以我们选择工厂方法模式
我们创建工厂class如下图:
public abstract class ItemFactory {
abstract Item getItem();
}
class CakeFactory extends ItemFactory {
@Override
Item getItem() {
return new Cake();
}
}
class ChocolateFactory extends ItemFactory {
@Override
Item getItem() {
return new Chocolate();
}
}
class Client{
public static void main(String[] args) {
Item chocolate = new ChocolateFactory().getItem();
System.out.println(chocolate);
}
}
现在,当客户端想要添加名为 IceCream 的新项目时,他们只需创建名为 IceCreamFactory 的新工厂并从中创建 IceCream,如下所示:
class IceCreamFactory extends ItemFactory{
@Override
Item getItem() {
return new IceCream();
}
}
class Client{
public static void main(String[] args) {
Item iceCream = new IceCreamFactory().getItem();
System.out.println(iceCream);
}
}
我的理解对吗? 我们在这里满足了开闭原则,但是对于每个产品(Item)我们需要一个工厂class,这不是成为可管理的噩梦吗?
我认为在您的示例中,工厂似乎毫无用处,因为您的 Cake 和 Chocolate 构造函数不需要任何参数。
当您想构造一个具有许多参数的复杂对象以遵守 DIP(依赖倒置原则)并避免令人尴尬的耦合时,工厂很有用。
另外,你的例子好像违反了LSP(Liskov Substitution Principle)。 Cake 和 Chocolate class 没有任何共同点,作为证据,您的抽象超级 class 被命名为 Item,这是一个非常通用的名称。
对我来说,对于复杂的不常见对象,class选择一个工厂更好,并且有效地尊重OCP(开闭原则)。
您的第一个示例对于实例化 classes 很有用,它继承了相同的 superclass,但是使用您的 classes 作为参数和反射(使用 java.lang.reflect ) 来调用构造函数,而不仅仅是使用 String 求值。 (您的 IDE 无法自动完成)并且在不匹配的情况下不要 return null,抛出 IllegalArgumentException,它更正确。
像这样:
import java.lang.reflect.Constructor;
public class SimpleItemFactory {
public <T extends Item> T createItem(Class<? extends Item> itemClass) {
try {
// construct your dependencies here
// and inject them in the getConstructor
Constructor<? extends Item> constructor = itemClass.getConstructor();
return (T)constructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException();
}
}
}
并像这样使用它:
class Client {
public static void main(String[] args) {
SimpleItemFactory factory = new SimpleItemFactory();
IceCream iceCream = factory.createItem(IceCream.class);
System.out.println(iceCream);
Cake cake = factory.createItem(Cake.class);
System.out.println(cake);
Chocolate chocolate = factory.createItem(Chocolate.class);
System.out.println(chocolate);
}
}
如果您没有依赖项,则可以直接在您的抽象项 class 中将 createItem() 方法实现为静态方法。
看看这本书,这是一个很好的资源:Head First Design Patterns
OCP只是Open for extension Close for modification的原则。如果你需要打开修改你的工厂来添加一个新的class(一个新的案例在一个开关或一个if中管理),不,你的工厂不是"OCP"。
你不应该在构造函数中计算税收,构造函数应该只是......构造一个对象......你可以使用类似策略的模式来拥有许多taxCalculator并将它们注入构造函数,使用IOC(控制反转)机制,例如依赖项注入或以简单的方式使用.....工厂(这是可以接受的),但不能使用 class 中的简单静态方法。
对不起我的英语不好,我很难回答这样复杂的问题。
其实你的理解是正确的,只是你需要注意,每个设计模式都是为了解决至少一个问题,有时它可能会带来其他问题复杂性或副作用,这意味着没有完美的设计模式可以解决所有问题。
为了学习的目的,你一个一个地应用设计模式(这使得设计模式的真正力量同样是害羞或隐藏),但是在现实世界中,设计模式是混合在一起的(或者你甚至可以发明一个新的 :p) 为了创造满足您的大部分需求并接近理想的东西,您可以遇到例如 Builder 模式与 Factory 模式的混合或 Factory 模式与 Strategy 模式的混合,甚至他们三个混合在一起。 ..
对于您的情况,我建议例如使用 Factory Method Pattern 以及 Simple Factory Pattern 和 依赖注入模式 创造出完全美丽的东西,同时满足 Open closed 原则。
class ItemFactoryContainer() {
private Map<String, ItemFactory> factories = new HashMap<>();
public void register(String name, ItemFactory factory) {
factories.put(name, factory);
}
public ItemFactory getFactory(String name) {
return factories.get(name);
}
}
public class ItemFactoryTest {
public static void main(String...args) {
ItemFactoryContainer factoryContainer = new ItemFactoryContainer();
factoryContainer.register("choclate", new ChocolateFactory ());
factoryContainer.register("cake", new CakeFactory ());
factoryContainer.register("iceCream", new IceCreamFactory ());
Chocolate choclate = factoryContainer.getFactory("choclate").getItem();
Cake cake = factoryContainer.getFactory("cake").getItem();
}
}
答案(@Mouad EL Fakir 和@François LEPORCQ)是关于静态工厂的。那是你的代码的第一部分。
还有两种风格,即工厂方法和抽象工厂)
你的代码的第二部分正在使用 CakeFactory 和 ChocolateFactory,你正在尝试使用工厂方法(尽管你的命名暗示抽象工厂)。这里工厂方法getXXX()的用法是不正确的。这些模式的目的是不同的。在您的代码中,除了增加 类 的数量外,您没有取得任何成就。 (尽管 增加的 类 和 平行层次结构 被记录为与工厂相关的成本)
我最近回答过类似的问题,看看这些回答是否有帮助