工厂模式
目录
定义
工厂模式属于创建型设计模式,它用于解耦对象的创建和使用。通常情况下,我们创建对象时需要使用new
操作符,但是使用new
操作符创建对象会使代码具有耦合性。工厂模式通过提供一个公共的接口,使得我们可以在不暴露对象创建逻辑的情况下创建对象。
分类
工厂模式主要分为三种类型:
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
工厂模式核心角色
- 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
- 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
- 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。
简单工厂模式
定义
简单工厂模式是一种创建型设计模式,它提供了一个静态方法(或其他静态机制)来封装对象的创建过程,客户端只需要传入相应的参数,就可以获取到所需要的对象实例,而无需关心具体的创建细节。
特点
- 工厂类包含必要的判断逻辑,根据客户端的请求,决定返回哪一个产品类的实例。
- 客户端只需要知道产品的抽象接口和工厂类,而无需知道具体的产品实现类。
- 将对象的创建与使用解耦,降低了系统的耦合度。
优点
- 客户端无需知道对象的创建细节,只需要知道具体工厂类和对应的参数。
- 将对象的创建和使用分离,使得系统结构更加清晰。
- 提高了系统的可扩展性,当需要增加新的产品时,只需要增加相应的产品类和修改工厂类即可。
缺点
- 工厂类集中了所有产品类的创建逻辑,违反了“单一职责原则”。
- 当产品类族增加时,工厂类的修改和维护会变得复杂。
- 简单工厂模式没有使用面向对象的多态性,而是使用了条件语句来选择要创建的对象,这可能导致系统难以扩展和维护,违反了“开闭原则”(对扩展开放,对修改关闭)。
应用场景
- 当一个系统需要创建的对象较少且创建逻辑相似时,可以考虑使用简单工厂模式。
- 客户端只需要知道传入工厂类的参数,而不关心创建对象的细节时。
- 工厂类负责创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂。
代码实现
// 产品接口
interface Shape {
void draw();
}
// 具体产品类 Circle
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
// 具体产品类 Rectangle
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// 工厂类
class ShapeFactory {
// 使用静态方法创建对象
public static Shape getShape(String shapeType) {
if ("CIRCLE".equalsIgnoreCase(shapeType)) {
return new Circle();
} else if ("RECTANGLE".equalsIgnoreCase(shapeType)) {
return new Rectangle();
}
return null;
}
}
// 客户端代码
public class FactoryPatternDemo {
public static void main(String[] args) {
Shape shape1 = ShapeFactory.getShape("CIRCLE");
shape1.draw();
Shape shape2 = ShapeFactory.getShape("RECTANGLE");
shape2.draw();
}
}
工厂方法模式
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
特点
- 核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给它的子类去做。
- 客户端针对抽象工厂类编程,不依赖于具体工厂类,符合依赖倒置原则。
- 子类可以方便地扩展新的产品类,只需要增加新的具体产品类和对应的具体工厂类,原有工厂类体系不需要做任何修改,符合开闭原则。
优点
- 用户只需要知道具体工厂类的名称就可得到所要的产品,无须知道产品的具体类名。
- 通过在工厂接口中定义创建产品的方法,将产品的创建与使用分离,使得系统的扩展性更好。
- 在产品类家族增加新的产品时,只需要增加新的产品类和对应的工厂类,原有系统无须做任何修改,符合“开闭原则”。
缺点
- 当产品类族增加时(即增加一个产品接口和多个实现类),就需要增加一个新的工厂接口和多个具体的工厂实现类,这样会增加系统的复杂度。
- 客户端需要知道新增的工厂接口,并对代码进行修改扩展,在一定程度上增加了客户端的复杂性。
应用场景
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者是这一信息局部化的时候。
代码实现
// 产品接口
interface Product {
void use();
}
// 具体产品类A
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using product A.");
}
}
// 具体产品类B
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using product B.");
}
}
// 抽象工厂类
abstract class Creator {
public abstract Product factoryMethod();
}
// 具体工厂类A
class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具体工厂类B
class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
// 客户端代码
public class FactoryMethodDemo {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.use(); // 输出 "Using product A."
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.use(); // 输出 "Using product B."
}
}
抽象工厂模式
定义
抽象工厂模式是一种为访问一系列相互关联或相互依赖的对象提供一个接口,而无需指定它们具体的类。在抽象工厂模式中,有一个抽象工厂接口定义了创建产品对象的操作接口,但由子类来决定实例化哪一个类。客户端则针对抽象工厂接口编程,不依赖于具体的工厂实现。
特点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。
- 将一个系列的产品族统一到一起创建。
- 每一个产品族都有一个具体的工厂,负责创建具体产品对象。
优点
-
易于交换产品系列,由于一个具体的工厂类只在一个产品族中创建产品对象,使得将一个产品族替换成另一个产品族变得容易,它只需要改变具体的
-
工厂类即可。 2. 有利于产品的一致性,当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。 3. 提高系统的可扩展性,增加新的产品族很方便,无需修改已有的系统,符合开闭原则。
缺点
- 抽象工厂模式增加了系统的抽象性和理解难度,不易于理解和修改;
- 新增产品族时需要修改工厂接口、工厂实现类和产品类,增加了系统的复杂性。
应用场景
- 当一个系统需要独立地变化产品的族时。
- 当系统需要多个产品族,并且这些产品族之间是相互关联的。
- 当需要创建复杂对象时,抽象工厂模式可以简化创建过程。
代码实现
// 产品接口A interface ProductA { void use(); } // 产品接口B interface ProductB { void assemble(); } // 产品A的实现类1 class ConcreteProductA1 implements ProductA { @Override public void use() { System.out.println("Using product A1."); } } // 产品A的实现类2 class ConcreteProductA2 implements ProductA { @Override public void use() { System.out.println("Using product A2."); } } // 产品B的实现类1 class ConcreteProductB1 implements ProductB { @Override public void assemble() { System.out.println("Assembling product B1."); } } // 产品B的实现类2 class ConcreteProductB2 implements ProductB { @Override public void assemble() { System.out.println("Assembling product B2."); } } // 抽象工厂接口 interface AbstractFactory { ProductA createProductA(); ProductB createProductB(); } // 具体工厂类1 class ConcreteFactory1 implements AbstractFactory { @Override public ProductA createProductA() { return new ConcreteProductA1(); } @Override public ProductB createProductB() { return new ConcreteProductB1(); } } // 具体工厂类2 class ConcreteFactory2 implements AbstractFactory { @Override public ProductA createProductA() { return new ConcreteProductA2(); } @Override public ProductB createProductB() { return new ConcreteProductB2(); } } // 客户端代码 public class Client { public static void main(String[] args) { AbstractFactory factory1 = new ConcreteFactory1(); ProductA productA1 = factory1.createProductA(); ProductB productB1 = factory1.createProductB(); productA1.use(); productB1.assemble(); AbstractFactory factory2 = new ConcreteFactory2(); ProductA productA2 = factory2.createProductA(); ProductB productB2 = factory2.createProductB(); productA2.use(); productB2.assemble(); } }
工厂模式小结
工厂方法模式与抽象工厂模式的区别在于:
- 工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例;
- 抽象工厂模式拥有多个产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例。
工厂模式提供了一种创建对象的机制,使得对象的创建和使用分离,提高了代码的可维护性和可扩展性。在实际开发中,根据具体需求选择合适的工厂模式,可以有效地简化对象创建过程,降低系统复杂度。