Java设计模式之三:工厂方法模式详细解析

一、简单工厂模式的不足

  1. 对于每种产品类型的创建都依赖于一个共同的工厂类,这违背了开放封闭原则,当需要新增产品类型时,需要修改工厂类的代码,不符合单一职责原则。
  2. 工厂类集中了所有产品的创建逻辑,导致该类的代码通常会随着产品类型的增加而变得庞大臃肿,不易维护和扩展。
  3. 简单工厂模式将产品的创建逻辑集中在一个工厂类中,当工厂类出现问题导致无法创建产品时,整个系统将无法正常工作。

 

二、工厂方法模式相比于简单工厂模式的不同与好处

2.1工厂方法模式相比于简单工厂模式的区别

  1. 结构不同:

    • 简单工厂模式只有一个具体工厂类,该具体工厂类根据不同的参数或条件创建不同的产品对象。
    • 工厂方法模式引入了抽象工厂类和具体工厂类的层次结构,每个具体工厂类只负责创建特定的产品对象。
  2. 对象创建的职责不同:

    • 简单工厂模式中,具体工厂类负责创建所有产品对象。
    • 工厂方法模式中,每个具体工厂类只负责创建特定类型的产品对象,从而将对象创建的职责进行了分离。
  3. 扩展性不同:

    • 对于简单工厂模式,当需要添加新产品时,需要修改简单工厂类的创建逻辑,违背了开放封闭原则。
    • 工厂方法模式通过添加新的具体工厂类和产品类来扩展,符合开放封闭原则,并且不会修改已有的代码。

 

2.2工厂方法模式相比于简单工厂模式的优点

  1. 符合开放封闭原则,新增产品类型时无需修改已有代码,只需添加新的具体工厂类即可。
  2. 每个产品类型有专门的工厂类负责创建,降低了工厂类的复杂度,符合单一职责原则和高内聚低耦合的设计原则。
  3. 工厂方法模式可以针对不同的产品类型,实现不同的工厂类,从而实现产品创建的灵活性和扩展性。

 

三、工厂方法模式的定义与结构

工厂方法模式的定义:
工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但将实际创建对象的过程延迟到子类中,从而使得系统可以在不修改原有代码的情况下引入新的产品类型。

工厂方法模式的结构:

  1. 抽象产品(Product):定义了产品的通用接口。
  2. 具体产品(ConcreteProduct):实现抽象产品接口的具体产品类。
  3. 抽象工厂(Creator):定义了创建产品的抽象工厂方法。
  4. 具体工厂(ConcreteCreator):实现抽象工厂接口,负责具体产品对象的创建。

 

四、工厂方法模式的模式分析

  1. 角色和职责:

    • 抽象工厂(Abstract Factory):定义创建产品对象的工厂接口,包含了创建产品的抽象方法。
    • 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建具体的产品对象。
    • 抽象产品(Abstract Product):定义产品的接口,描述了产品的功能。
    • 具体产品(Concrete Product):实现抽象产品接口,定义具体产品的具体功能。
  2. 工作流程:

    • 客户端通过调用具体工厂类的方法来创建产品对象,而不是直接调用产品的构造函数。
    • 具体工厂类会根据客户端的请求创建相应的产品对象,客户端并不关心具体是哪个具体工厂类创建的产品对象。

总结起来,工厂方法模式通过将对象的创建委托给具体工厂类来实现对象的创建,以达到将对象创建和使用的解耦。它提供了一种灵活的方式来创建对象,同时增加新的产品类型也相对简单。

 

五、工厂方法模式具体的代码举例

5.1披萨店生产披萨

假设有一个披萨店,店内提供多种口味的披萨。抽象产品类定义了披萨的通用接口,具体产品类实现了不同口味的具体披萨,抽象工厂类定义了创建披萨的抽象工厂方法,具体工厂类实现了具体口味披萨的创建过程。

产品类:

// 抽象产品类
interface Pizza {
    void prepare();
    void bake();
    void cut();
}

// 具体产品类
class CheesePizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备芝士披萨的原材料");
    }

    @Override
    public void bake() {
        System.out.println("烘烤芝士披萨");
    }

    @Override
    public void cut() {
        System.out.println("切割芝士披萨");
    }
}

class PepperoniPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备意大利辣香肠披萨的原材料");
    }

    @Override
    public void bake() {
        System.out.println("烘烤意大利辣香肠披萨");
    }

    @Override
    public void cut() {
        System.out.println("切割意大利辣香肠披萨");
    }
}

 工厂类:

// 抽象工厂类
interface PizzaFactory {
    Pizza createPizza();
}

// 具体工厂类
class CheesePizzaFactory implements PizzaFactory {
    @Override
    public Pizza createPizza() {
        return new CheesePizza();
    }
}

class PepperoniPizzaFactory implements PizzaFactory {
    @Override
    public Pizza createPizza() {
        return new PepperoniPizza();
    }
}

客户端:

// 客户端
public class Main {
    public static void main(String[] args) {
        PizzaFactory factory = new CheesePizzaFactory();
        Pizza cheesePizza = factory.createPizza();
        cheesePizza.prepare();
        cheesePizza.bake();
        cheesePizza.cut();

        factory = new PepperoniPizzaFactory();
        Pizza pepperoniPizza = factory.createPizza();
        pepperoniPizza.prepare();
        pepperoniPizza.bake();
        pepperoniPizza.cut();
    }

 

该代码实现了一个简单的工厂方法模式的例子,其中有以下几个关键部分:

  1. 抽象产品类 Pizza:

    • 定义了披萨的接口,包括准备原材料、烘烤和切割等方法。
  2. 具体产品类 CheesePizza 和 PepperoniPizza:

    • 实现了抽象产品类 Pizza 的接口,分别表示芝士披萨和意大利辣香肠披萨。
  3. 抽象工厂类 PizzaFactory:

    • 定义了创建 Pizza 对象的工厂接口,包含一个创建 Pizza 的抽象方法 createPizza。
  4. 具体工厂类 CheesePizzaFactory 和 PepperoniPizzaFactory:

    • 分别实现了抽象工厂类 PizzaFactory 的接口,负责创建具体的 Pizza 对象。
  5. 客户端类 Main:

    • 创建具体的工厂对象(例如 CheesePizzaFactory)。
    • 使用工厂对象的 createPizza 方法创建具体的 Pizza 对象。
    • 调用 Pizza 对象的 prepare、bake 和 cut 方法。

通过调用具体工厂类的 createPizza 方法,客户端可以获得相应的具体产品对象,而不需要直接与具体产品类进行耦合。这符合了工厂方法模式的核心思想。在示例中,客户端先使用 CheesePizzaFactory 创建了一个 CheesePizza 对象,然后调用其相关方法进行操作;接着,客户端使用 PepperoniPizzaFactory 创建一个 PepperoniPizza 对象,并调用其相关方法。

这种结构有助于将对象的创建过程进行封装和解耦,而且当需要新增具体产品类型时,只需要添加相应的具体工厂类和具体产品类即可,不会对已有的代码造成修改。

 

5.2手机工厂

这里再举一个工厂方法模式的例子:手机工厂。

// 抽象产品类
interface Phone {
    void call();
    void sendMessage();
}

// 具体产品类
class IPhone implements Phone {
    @Override
    public void call() {
        System.out.println("使用 iPhone 打电话");
    }

    @Override
    public void sendMessage() {
        System.out.println("使用 iPhone 发送短信");
    }
}

class SamsungPhone implements Phone {
    @Override
    public void call() {
        System.out.println("使用三星手机打电话");
    }

    @Override
    public void sendMessage() {
        System.out.println("使用三星手机发送短信");
    }
}

// 抽象工厂类
interface PhoneFactory {
    Phone createPhone();
}

// 具体工厂类
class IPhoneFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new IPhone();
    }
}

class SamsungPhoneFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new SamsungPhone();
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        PhoneFactory factory = new IPhoneFactory();
        Phone iPhone = factory.createPhone();
        iPhone.call();
        iPhone.sendMessage();

        factory = new SamsungPhoneFactory();
        Phone samsungPhone = factory.createPhone();
        samsungPhone.call();
        samsungPhone.sendMessage();
    }
}

 

这个例子中,我们有两种具体产品:iPhone 和三星手机,它们都实现了抽象产品 Phone 的接口,具有打电话和发送短信的功能。

抽象工厂类 PhoneFactory 定义了创建手机对象的接口,其中包含一个抽象方法 createPhone()。

具体工厂类 IPhoneFactory 和 SamsungPhoneFactory 分别实现了抽象工厂类 PhoneFactory 的接口,用于创建具体的手机对象。

在客户端中,我们首先使用 IPhoneFactory 创建一个 iPhone 对象,并调用其相关方法;然后使用 SamsungPhoneFactory 创建一个三星手机对象,并调用其相关方法。

工厂方法模式通过将对象的创建委托给具体的工厂类,使得客户端与具体的产品类解耦。新加入一种手机类型时,只需要新增对应的具体工厂类和具体产品类,不需要修改已有的代码,符合开放封闭原则。

 

六、工厂方法模式优缺点

工厂方法模式的优点:

  1. 符合开放封闭原则:新增产品类型时只需添加新的具体工厂类和产品类,无需修改已有代码,系统可扩展性较好。
  2. 高内聚低耦合:每个产品类型由专门的具体工厂类负责创建,降低了模块间的耦合度,使得系统更加灵活、可维护和可扩展。
  3. 管理单一职责原则:每个具体工厂类只负责创建相应的产品,符合单一职责原则,使得系统结构更清晰。

工厂方法模式的缺点:

  1. 类的个数增加:每增加一个新的产品,都需要提供一个具体产品类和一个对应的具体工厂类,这样会导致类的个数成倍增长,增加了系统复杂度。
  2. 引入了许多具体工厂类:随着产品类型的增加,可能会引入大量具体工厂类,增加了系统的抽象性和理解难度。

需要根据具体的场景和需求来选择合适的设计模式,工厂方法模式适用于产品种类较多,但对于扩展新产品的需求较为频繁的情况。

 

 

你可能感兴趣的:(java,设计模式,工厂方法模式)