设计模式之----工厂模式及抽象工厂模式

本文详细介绍了工厂模式、工厂方法模式及抽象工厂模式的概念与应用。通过披萨店与电子产品制造两个案例,展示了如何利用这些设计模式解决对象创建时的耦合问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计模式之工厂模式及抽象工厂模式

  • 工厂方法模式以及抽象工厂模式
  • 工厂模式案例一
  • 工厂模式案例二
  • 小结

工厂方法模式以及抽象工厂模式

  • 工厂方法 : 定义一个创建对象的接口(抽象方法),让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程(实例化)延迟到子类进行。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
  • 抽象工厂: 提供一个创建一系列相关或相互依赖对象的接口(对象族),而无需指定它们具体的类。抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

工厂模式案例一

通过烘烤披萨并且完善相关的订单系统来看工厂模式,披萨有各种各样的,用户通过点不同的披萨,后台不断的完成相应的工作,即准备相应的披萨、烘烤、切片、打包。

这里写图片描述

(1)首先看一个不好的设计方案 :

这里写图片描述
各种Pizza类的父类

package factory.Bad.pizza;
/**
 * Pizza超类
 */
public abstract class Pizza {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //抽象方法,子类具体不同的实现
    public abstract void prepare();


    //不需要子类实现的(抽象类里面已经实现了)
    public void bake(){
        System.out.println(name + "  baking !");
    }

    public void cut(){
        System.out.println(name + "  cutting !");
    }

    public void box(){
        System.out.println(name + "  boxing !");
    }
}

然后是几个Pizza子类:

package factory.Bad.pizza;

public class CheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("CheesePizza");
        System.out.println(getName() + "  preparing!");
    }
}
package factory.Bad.pizza;

public class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        setName("GreekPizza");
        System.out.println(getName() + "  preparing!");
    }
}
package factory.Bad.pizza;

public class PepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("PepperPizza");
        System.out.println(getName() + "  preparing!");
    }
}

然后是下单的类:

package factory.Bad.order;

import factory.Bad.pizza.CheesePizza;
import factory.Bad.pizza.GreekPizza;
import factory.Bad.pizza.PepperPizza;
import factory.Bad.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {

    //直接在构造函数中
    public OrderPizza() {
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            if(orderType.equals("cheese")){
                pizza = new CheesePizza();
            }else if(orderType.equals("greek")){
                pizza = new GreekPizza();
            }else if(orderType.equals("pepper")){
                pizza = new PepperPizza();
            }else { //输入异常
                break;
            }
            //开始烘烤包装
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();

        }while(true);
    }

    //输入相应的种类
    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input  pizza type : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类:

package factory.Bad.test;

import factory.Bad.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
        OrderPizza orderPizza = new OrderPizza();
    }
}

测试情况
这里写图片描述

  • 上面的测试方案的不好之处在于如果我们想增加新的披萨,就需要修改订单中的if esle语句,每次增加,都要修改
  • 所以对于可能以后会变化的地方,我们可以封装成另一个类,抽取出来,降低耦合度。
(2)使用简单工厂模式

这里写图片描述

我们可以把需要改变的那部分抽取出来成为一个类: (所以简单工厂模式很简单,只是把之前的可以变化的部分抽取出来)
这里写图片描述
我们看OrderPizza类和SimplePizzaFactory类,和上面的代码只有这里有变化:

package factory.SimpleFactory.factory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;

public class SimplePizzaFactory {
    /**
     * 这个方法也可以写成 静态的,,这样在  OrderPizza类中就不需要传入这个类的对象了
     * (不过写成静态的也有不好的地方,不能通过继承来改变创建的行为)
     */
    public Pizza createPizza(String orderType){
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new CheesePizza();
        }else if(orderType.equals("greek")){
            pizza = new GreekPizza();
        }else if(orderType.equals("pepper")){
            pizza = new PepperPizza();
        }
        return pizza;
    }
}

OrderPizza类中要有SimplePizzaFactory类的对象引用

package factory.SimpleFactory.order;

import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {

    SimplePizzaFactory simplePizzaFactory;

    public OrderPizza(SimplePizzaFactory simplePizzaFactory) {
        this.simplePizzaFactory = simplePizzaFactory;
        setFactory();
    }
    //直接在构造函数中
    public void setFactory() {
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = simplePizzaFactory.createPizza(orderType);
            if (pizza != null) {
                //开始烘烤包装
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }

        }while(true);
    }

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza type : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类

package factory.SimpleFactory.test;

import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
        OrderPizza orderPizza = new OrderPizza(new SimplePizzaFactory());
    }
}

测试效果和之前是一样的。

(3)使用工厂方法模式

上面的方法可以解决耦合的问题,但是如果我们还有很多连锁披萨店,而且各个地方的披萨必须带上自己的特色,那么我们就可以使用工厂方法设计模式

这里写图片描述
这里写图片描述
先看几个有特色的披萨

package factory.FactoryMethod.pizza;
/**
 * Pizza超类
 */
public abstract class Pizza {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //抽象方法,子类具体不同的实现
    public abstract void prepare();


    //不需要子类实现的(抽象类里面已经实现了)
    public void bake(){
        System.out.println(name + "  baking !");
    }

    public void cut(){
        System.out.println(name + "  cutting !");
    }

    public void box(){
        System.out.println(name + "  boxing !");
    }
}
package factory.FactoryMethod.pizza;

public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("LDCheesePizza");
        System.out.println(getName() + "  preparing !");
    }
}
package factory.FactoryMethod.pizza;

public class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("LDPepperPizza");
        System.out.println(getName() + "   preparing!");
    }
}
package factory.FactoryMethod.pizza;

public class NYCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("NYCheesePizza");
        System.out.println(getName() + "  preparing !");
    }
}
package factory.FactoryMethod.pizza;

public class NYPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("NYPepperPizza");
        System.out.println(getName() + "  preparing!");
    }
}

然后就是三个”工厂”,把OrderPizza设计成抽象类,然后LDOrderPizza和NYOrderPizza都继承自OrderPizza:

package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public abstract class OrderPizza {

    public OrderPizza(){
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = createPizza(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        }while(true);
    }

    //子类实现
    public abstract Pizza createPizza(String orderType);

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza type  : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}
package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.NYCheesePizza;
import factory.FactoryMethod.pizza.NYPepperPizza;
import factory.FactoryMethod.pizza.Pizza;

public class NYOrderPizza extends OrderPizza  {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new NYCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new NYPepperPizza();
        }
        return pizza;
    }
}
package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.LDCheesePizza;
import factory.FactoryMethod.pizza.LDPepperPizza;
import factory.FactoryMethod.pizza.Pizza;

public class LDOrderPizza extends OrderPizza {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new LDCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

测试类:

package factory.FactoryMethod.test;

import factory.FactoryMethod.order.LDOrderPizza;
import factory.FactoryMethod.order.NYOrderPizza;
import factory.FactoryMethod.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
//        OrderPizza orderPizza = new LDOrderPizza();
        OrderPizza orderPizza = new NYOrderPizza();
    }
}

测试纽约的披萨效果
这里写图片描述

(4)使用抽象工厂模式

这里写图片描述
这里写图片描述
就是明确的指定一个抽象工厂,以及下面的子工厂,具体设计如下:
先看三个工厂

package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.Pizza;

public interface AbsFactory {
    public Pizza createPizza(String orderType);
}
package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.LDCheesePizza;
import factory.AbstractFactory.pizza.LDPepperPizza;
import factory.AbstractFactory.pizza.Pizza;

public class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new LDCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}
package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.NYCheesePizza;
import factory.AbstractFactory.pizza.NYPepperPizza;
import factory.AbstractFactory.pizza.Pizza;

public class NYFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new NYCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new NYPepperPizza();
        }
        return pizza;
    }
}

然后是点单系统: 里面有总工厂对象的引用:

package factory.AbstractFactory.order;

import factory.AbstractFactory.factory.AbsFactory;
import factory.AbstractFactory.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {
    AbsFactory absFactory;

    public OrderPizza(AbsFactory absFactory) {
        this.absFactory = absFactory;
        setFactory();
    }

    private void setFactory() {
        Pizza pizza = null;
        String orderType;

        do {
            orderType = getType();
            pizza = absFactory.createPizza(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                break;
            }

        }while (true);
    }

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza  type  : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类:

package factory.AbstractFactory.test;

import factory.AbstractFactory.factory.LDFactory;
import factory.AbstractFactory.factory.NYFactory;
import factory.AbstractFactory.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
//        OrderPizza orderPizza = new OrderPizza(new LDFactory());
        OrderPizza orderPizza2 = new OrderPizza(new NYFactory());
    }
}

运行效果和工厂模式一样。

工厂模式案例二

再看一个模拟鼠标,键盘,耳麦为产品,惠普,戴尔为工厂的例子。

(1)使用简单工厂模式

这里写图片描述
这里写图片描述
Mouse

package factory.practice.SimpleFactory;

public abstract class Mouse {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void display();
}
package factory.practice.SimpleFactory;

public class DellMouse extends Mouse {

    public DellMouse(){
        setName("DellMouse");
    }
    @Override
    public void display() {
        System.out.println(getName() + " ! ");
    }
}
package factory.practice.SimpleFactory;

public class HpMouse extends Mouse {

    public HpMouse() {
        setName("HpMouse");
    }

    @Override
    public void display() {
        System.out.println(getName() + " ! ");
    }
}

Mouse工厂(根据类型生成不同工厂的鼠标)

package factory.practice.SimpleFactory;

public class MouseFactory {

    public static Mouse createMouse(String type){
        if(type.equals("dell")){
            return new DellMouse();
        }else if(type.equals("hp")){
            return new HpMouse();
        }
        return null;
    }

}

测试

package factory.practice.SimpleFactory;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class MyTest {

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        String type = cin.nextLine();
        Mouse mouse = MouseFactory.createMouse(type);
        mouse.display();
    }
}

效果
这里写图片描述


(2)使用工厂模式

这里写图片描述

这里写图片描述
三个工厂

package factory.practice.FactoryMethod;

public interface MouseFactory {

    Mouse createMouse();
}
package factory.practice.FactoryMethod;

public class DellMouseFactory implements MouseFactory {
    @Override
    public Mouse createMouse() {
        return new DellMouse();
    }
}
package factory.practice.FactoryMethod;

public class HpMouseFactory implements MouseFactory {
    @Override
    public Mouse createMouse() {
        return new HpMouse();
    }
}

其他的鼠标类不变(就不重复贴了)
测试类

package factory.practice.FactoryMethod;

public class MyTest {
    public static void main(String[] args) {
        MouseFactory mouseFactory = new DellMouseFactory();
        mouseFactory.createMouse().display();
    }
}

效果

DellMouse ! 
(3)使用抽象工厂

这个是当我们在抽象工厂中添加多个方法(就是说PC厂商不仅生成鼠标,还要生产键盘),就成为了抽象工厂。

这里写图片描述
这里写图片描述
代码就不贴了放在我的github代码仓库


小结

这里写图片描述

工厂方法要多加练习,才能在实际项目中好好运用,这里还给出一个讲的好的博客

### 抽象工厂模式概述 抽象工厂模式是一种创建型设计模式,其核心在于提供了一种方式来创建一系列相关或相互依赖的对象,而不必指定它们的具体类[^2]。通过这种方式,客户端能够使用统一的接口来获取所需的产品实例,从而降低了系统组件之间的耦合度。 #### 模式的结构与工作原理 该模式主要由四个部分组成: - **抽象工厂(Abstract Factory)**:定义了一个用于创建一族具体产品对象的方法集合。 - **具体工厂(Concrete Factory)**:实现了抽象工厂所声明的操作,负责生产特定种类的产品系列。 - **抽象产品(Abstract Product)**:为每一种可能被生产的物品设定了通用接口。 - **具体产品(Concrete Product)**:实际要创建出来的实体类,继承自相应的抽象产品并实现其功能。 当客户请求某个类型的对象时,会调用相应工厂里的方法得到想要的结果;由于整个过程中只涉及到高层模块对于低层模块的引用(即仅知道如何操作抽象级别的成员),因此即使内部逻辑发生变化也不会影响到外部使用者。 #### 应用场景分析 此模式非常适合应用于以下情况: - 当应用程序存在多个可互换的产品线,并希望保持独立性以便于扩展新特性时不破坏现有代码; - 需要在运行期间动态决定应该采用哪一套设计方案来进行构建; - 要求确保同一版本下的各个组成部分始终一致地协同运作。 例如,在图形库中可以根据不同的渲染引擎选择合适的形状绘制器(如OpenGL vs DirectX)。再比如操作系统风格切换工具里根据不同主题调整窗口控件外观等都是很好的例子。 #### Java实现案例展示 下面给出一段简单的Java代码片段用来说明上述概念的应用: ```java // 定义两个层次的产品接口 public interface GUIFactory { Button createButton(); } public interface Button { void paint(); } ``` 接着分别针对WindowsMacOS平台定制化各自的GUI元素: ```java // Windows风格按钮 class WinButton implements Button { public void paint() { System.out.println("Render a button in the Windows style."); } } // MacOS风格按钮 class MacButton implements Button { public void paint() { System.out.println("Render a button in the macOS style."); } } ``` 最后建立对应的工厂类完成最终组装: ```java // 创建适用于Windows系统的UI部件制造者 class WinFactory implements GUIFactory { @Override public Button createButton() { return new WinButton(); } } // 创建适用于macOS系统的UI部件制造者 class MacFactory implements GUIFactory { @Override public Button createButton() { return new MacButton(); } } ``` 这样就可以很容易地根据当前环境配置选取适当的主题样式了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值