工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象的过程中将对象的创建和使用分离开来。它通过提供一个通用的接口来创建对象,而不需要暴露对象的具体实现细节。工厂模式有助于降低代码的耦合性,提高代码的可维护性和可扩展性。
背景
在许多应用程序中,对象的创建可能涉及到复杂的逻辑,例如根据不同的条件选择创建不同类型的对象,或者需要执行一些初始化步骤。这种复杂性可能会导致代码重复和不易维护。
在面向对象编程中,通常希望降低类之间的耦合度,即减少一个类对其他类的依赖。直接在代码中使用 new
操作符来创建对象会导致高耦合度,因为这将导致类直接与具体的对象类型相关联。
当需要添加新的类或修改现有的类时,如果代码中存在大量的对象创建逻辑,那么这些变更将变得复杂并且容易出错。工厂模式可以帮助将对象创建逻辑封装在一个地方,使得代码更易于扩展和维护。
工厂模式可以利用多态性,允许客户端代码通过抽象接口或基类与工厂交互,而不需要关心具体的对象类型。
工厂模式还可以可以隐藏对象的实际创建细节,将其封装在工厂类中。这有助于保持代码的封装性和安全性。
结构
工厂模式通常涉及以下几个角色:
-
工厂接口(Factory Interface):这是一个接口,定义了创建对象的方法。具体的工厂类将实现这个接口,负责创建具体的对象。
-
具体工厂(Concrete Factory):具体工厂是实现工厂接口的类,它负责创建具体的产品对象。每个具体工厂通常对应一个特定的产品。
-
产品接口(Product Interface):产品接口定义了产品的通用属性和方法。具体的产品类将实现这个接口,以提供产品的具体实现。
-
具体产品(Concrete Product):具体产品是实现产品接口的类,它负责实现产品的具体行为和属性。
工厂模式有多种变体,其中包括以下主要类型:
-
简单工厂模式(Simple Factory Pattern):在简单工厂模式中,通常只有一个工厂类,它根据不同的参数来创建不同的产品对象。这种模式较为简单,但不够灵活。
-
工厂方法模式(Factory Method Pattern):工厂方法模式引入了一个抽象工厂接口,每个具体产品对应一个具体工厂类。这使得每个产品可以由不同的工厂创建,增强了灵活性。
-
抽象工厂模式(Abstract Factory Pattern):抽象工厂模式引入了多个工厂接口,每个工厂接口可以创建一组相关的产品。这种模式用于创建一组相互关联的对象,例如,创建一个操作系统的用户界面(UI)时,需要同时创建按钮、文本框等相关的 UI 组件。
优点
工厂模式的优点包括:
- 分离了对象的创建和使用,降低了耦合性。
- 可以轻松添加新的产品类,而不需要修改现有代码。
- 提供了一种标准的接口,用于创建对象,使得代码更易于维护和扩展。
缺点
工厂模式的缺点包括:
- 如果产品类的构造函数有多个参数或参数组合复杂,可能会导致工厂类的代码变得复杂。
- 增加了类的数量,特别是在抽象工厂模式中,会引入多个工厂接口和多个具体工厂类。
工厂模式在实际应用中非常常见,特别是在大型项目中,它有助于管理和组织对象的创建和使用,提高了代码的可维护性和可扩展性。
下面以制造手机为例介绍这几种工厂模式:
产品接口
java
abstract class Phone {
/**
* 获取品牌信息
*/
public abstract String getName();
/**
* 获取型号信息
*/
public abstract String getModel();
/**
* 获取价格信息
*/
public abstract BigDecimal getPrice();
/**
* 展示手机信息
*/
public void show(){
System.out.println("品牌:"+getName()+" 型号:"+getModel()+" 价格:"+getPrice());
}
}
具体产品
java
class HUAWEI extends Phone{
public HUAWEI() {
}
@Override
public String getName() {
return "华为";
}
@Override
public String getModel() {
return "mate 60";
}
@Override
public BigDecimal getPrice() {
return BigDecimal.valueOf(8999);
}
@Override
public void show() {
super.show();
}
}
class Apple extends Phone {
public Apple() {
}
@Override
public String getName() {
return "苹果";
}
@Override
public String getModel() {
return "14Pro Max";
}
@Override
public BigDecimal getPrice() {
return BigDecimal.valueOf(7999);
}
@Override
public void show() {
super.show();
}
}
简单工厂模式
简单工厂模式并不是一种设计模式,即不属于23种经典的设计模式,反而像一种编程习惯。
结构
简单工厂包含以下成分:
- 产品接口:定义产品的规范,描述了产品的主要特性和功能。
- 具体产品:实现或者继承抽象产品的子类。
- 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品对象。
实现
在上面手机的基础上添加一个具体的手机工厂即可实现简单工厂模式
java
class SimplePhoneFactory {
public Phone createPhone(String name){
Phone phone = null;
if("Apple".equals(name)){
phone = new Apple();
}else if("HUAWEI".equals(name)){
phone = new HUAWEI();
}else{
throw new RuntimeException("抱歉,没有该手机!");
}
return phone;
}
}
// 或者使用静态工厂的方式,避免需要创建工厂的麻烦(一种习惯)
class SimplePhoneFactory {
public static Phone createPhone(String name){
Phone phone = null;
if("Apple".equals(name)){
phone = new Apple();
}else if("HUAWEI".equals(name)){
phone = new HUAWEI();
}else{
throw new RuntimeException("抱歉,没有该手机!");
}
return phone;
}
}
编写一个Customer类来测试该工厂
java
class Customer {
public static void main(String[] args) {
SimplePhoneFactory factory = new SimplePhoneFactory();
Phone apple = factory.createPhone("Apple");
apple.show(); // 顾客查看手机信息
}
}
// 静态工厂
public class Customer {
public static void main(String[] args) {
Phone apple = PhoneFactory.createPhone("HUAWEI");
apple.show();
}
}
优点
简单工厂模式有以下优点:
- 降低耦合度:客户端代码只需要依赖工厂类,而不需要依赖具体的产品类。这降低了类之间的耦合度,使得代码更加灵活和可维护。
- 集中管理:通过使用简单工厂,可以将对象的创建集中管理。这有助于管理和维护对象的生命周期和创建逻辑。
- 易于扩展:如果需要添加新的产品类,只需修改工厂类的创建逻辑,而不需要修改客户端代码。这提高了系统的可扩展性。
- 符合面向对象的封装性:简单工厂模式将对象的创建逻辑封装在工厂类中,客户端不需要知道具体的对象创建细节。这有助于隐藏实现细节,使得客户端代码更简洁。
缺点
同时,它也含有以下缺点:
- 违反开闭原则:当需要添加新的产品类时,必须修改工厂类的代码来支持新的产品。这违反了开闭原则,即对扩展开放,对修改关闭。
- 不支持多态性:在简单工厂模式中,客户端通常需要通过具体产品的名称或标识来选择要创建的对象,而不是使用多态性。这降低了代码的灵活性。
- 工厂类臃肿:随着产品类型的增加,工厂类可能会变得庞大,并包含大量的条件语句来处理不同的产品类型,导致工厂类的维护困难。
- 不符合单一职责原则:工厂类既要负责对象的创建,又要负责选择创建哪种对象。这违反了单一职责原则,即一个类应该只有一个原因引起变化。
工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种将对象的创建延迟到子类的方式,以便子类可以决定要实例化的具体类。工厂方法模式是工厂模式家族中的一员,它有助于解决创建对象的问题,并提供了更高的灵活性和可扩展性。
思想
工厂方法模式的关键思想是将对象的创建委托给子类,每个具体的工厂子类负责创建一种特定类型的产品。这样可以使系统更容易扩展,因为当需要添加新的产品时,只需要创建一个新的具体工厂和具体产品类,而不需要修改现有的代码。
结构
工厂方法模式的主要组成部分:
-
抽象工厂接口(Factory Interface):这是一个接口或抽象类,它声明了一个用于创建产品的抽象方法。具体工厂类将实现这个接口以创建特定类型的产品。
-
具体工厂类(Concrete Factory):每个具体工厂类都实现了工厂接口,它负责创建一种具体类型的产品。每个工厂类通常与一个特定的产品相关联。
-
产品接口(Product Interface):产品接口定义了产品的通用属性和方法。具体的产品类将实现这个接口,以提供产品的具体实现。
-
具体产品类(Concrete Product):具体产品类实现了产品接口,它负责提供产品的具体实现。
实现
依旧以上面手机工厂为例。
抽象工厂接口
java
public interface PhoneFactory {
Phone createPhone();
}
具体的工厂类
java
class ApplePhoneFactory implements PhoneFactory{
@Override
public Phone createPhone() {
return new Apple();
}
}
class HUAWEIPhoneFactory implements PhoneFactory{
@Override
public Phone createPhone() {
return new HUAWEI();
}
}
这里为了方便,还创建了一个PhoneStore手机店类来对接手机工厂,这样也更符合实际逻辑。
java
class PhoneStore {
private PhoneFactory factory;
public void setFactory(PhoneFactory factory) {
this.factory = factory;
}
public Phone salePhone(){
return factory.createPhone();
}
}
添加顾客类测试工厂效果
java
class Customer {
public static void main(String[] args) {
// 创建手机店对象
PhoneStore store = new PhoneStore();
// 创建工厂对象
HUAWEIPhoneFactory factory = new HUAWEIPhoneFactory();
// 设置工厂对象
store.setFactory(factory);
// 购买手机
Phone phone = store.salePhone();
// 获取手机信息
phone.show();
}
}
使用场景
工厂方法模式的典型应用场景包括:
- 当一个类无法预知它需要创建的对象的类时,可以使用工厂方法模式。
- 当一个类希望由其子类来指定所创建的对象时,可以使用工厂方法模式。
- 当一个类需要将对象的创建延迟到其子类时,可以使用工厂方法模式。
优点
工厂方法模式的优点包括:
- 支持开闭原则:可以轻松添加新的产品类,而不需要修改现有的代码。
- 提供了更高的灵活性:每个具体工厂可以创建不同类型的产品,客户端代码不需要知道具体的产品类。
- 降低了客户端和具体产品之间的耦合度。
缺点
同时,工厂方法模式也存在一些缺点:
- 增加了类的数量:为每个具体产品都需要创建一个具体工厂类,可能导致类的数量增加。
- 客户端需要了解不同的工厂类:客户端代码需要知道使用哪个具体工厂类来创建对象,这可能会增加客户端的复杂性。