工厂方法模式有利于产品种类的扩展,只需要添加对应的产品类和具体工厂类即可扩展系统,而无需修改现有的代码,符合“开闭原则”。
同时,它也增加了系统的复杂性,并可能增加系统中类的数量,每增加一个产品就可能需要增加一个具体工厂类。
为了解决什么问题?
工厂方法模式主要解决产品类的扩展问题,即在不修改工厂类的情况下扩展产品类。
它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。这样的设计使一个类的实例化延迟到了其子类,降低了客户端与具体产品类之间的耦合,增加了代码的灵活性和可维护性。
怎么用代码实现?
下面是Java代码示例,先定义抽象产品:
/**
* 抽象产品
*/
interface Product {
void use();
}
然后定义具体的产品:
/**
* 具体产品A
*/
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProductA");
}
}
/**
* 具体产品B
*/
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProductB");
}
}
再定义工厂接口:
/**
* 创建者(工厂)接口
*/
interface Creator {
Product createProduct();
}
以及对应产品的产品工厂:
/**
* 具体创建者A
*/
class ConcreteCreatorA implements Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
/**
* 具体创建者B
*/
class ConcreteCreatorB implements Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
最后,在使用时用对应产品的工厂类来创建产品:
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.createProduct();
productA.use();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.createProduct();
productB.use();
为什么可以解决这个问题?
工厂方法模式通过让子类来决定应该实例化哪一个类来达到解耦的目的。这增加了系统的灵活性,因为可以在不改变客户端代码的情况下引入新的产品类。
通过定义一个创建对象的接口,将具体产品对象的创建推迟到子类中完成,从而实现了调用者和实现者的分离。
工厂方法模式适用于哪些场景?
工厂方法模式适用于以下几种场景:
创建对象时需要大量复用代码时:当创建逻辑需要许多步骤时,如果在多个地方出现,就会造成代码重复。工厂方法模式通过在一个方法中集中所有的实例化代码,减少了代码的重复。
系统需要灵活地添加产品时:如果你需要向程序中添加更多产品,不需要修改现有的客户端代码,只需添加相对应的新的具体产品类和相应的具体工厂类即可。这种扩展性遵循了开闭原则,即对扩展开放,对修改封闭。
当有一组类似的产品需要创建时:如果你有多个相似的产品(这些产品都满足同一个接口或者抽象类),并且它们之间只有实现上的不同。通过工厂方法,可以轻松实现一组具有相同接口的产品的实例化。
当一个类希望由它的子类来指定创建的对象时:有时候你可能需要延迟具体产品的创建到子类中,工厂方法允许子类决定创建哪一个对象,而父类中提供创建对象的接口方法。
需要将对象的创建和使用解耦时:工厂方法通过引入工厂接口,并让不同的工厂子类来负责具体产品的创建,客户端只和产品的接口或抽象类交互,从而实现了创建逻辑和使用逻辑的解耦。
工厂方法模式在开源代码中很常见,下面是一些经典的应用案例:
Java标准库:比如java.util.Calendar.getInstance()、java.text.NumberFormat.getInstance()等,都是工厂方法模式的典型应用,通过工厂方法提供了不同实现的实例。
Spring框架:在Spring框架中,BeanFactory是一个工厂的核心接口。它定义了IoC容器的最基本形态和功能,通过getBean()方法实现bean的创建和管理。
Logback:在Logback中,LoggerFactory.getLogger(name)方法会根据不同名称返回不同的Logger实例,这也是工厂方法模式的一个应用。
———————————这是分割线———————————
欢迎添加博主vx深入交流: