23种设计模式之工厂模式

工厂模式

工厂模式是一种创建对象的设计模式,将对象的创建和使用分离,可提高代码可维护性、可扩展性,封装复杂创建逻辑。其目的是隐藏对象创建的过程与细节。

在这里插入图片描述

工厂模式经典案例

国际化案例,根据用户的IP返回不同语言的界面。

在这里插入图片描述

工厂模式分类与优缺点

工厂模式主要分为三类:

一、简单工厂模式

简单工厂模式又称为静态工厂方法模式。它定义了一个创建对象的类,由这个类来封装实例化对象的行为。在简单工厂模式中,工厂类有一个创建产品对象的方法,这个方法可以根据传入的参数决定创建哪种具体的产品对象。

优点:实现了对象创建和使用的分离,客户端无需了解对象的具体创建过程,只需要关心如何使用对象。代码结构简单,容易理解和实现。

缺点:不符合开闭原则,即当需要增加新的产品对象时,需要修改工厂类的代码。

二、工厂方法模式

工厂方法模式是在简单工厂模式的基础上,将工厂类的创建方法抽象成抽象方法,由具体的工厂子类实现这些抽象方法来创建具体的产品对象。

优点:符合开闭原则,当需要增加新的产品对象时,只需要增加一个具体的工厂子类,无需修改原有代码。

缺点:工厂子类过多时,会导致代码结构复杂,增加系统的维护成本

三、抽象工厂模式

抽象工厂模式中,工厂类不再负责创建具体的产品对象,而是负责创建一系列相关的产品对象。客户端只需要调用抽象工厂的抽象创建方法,由具体的工厂子类来创建所需的产品对象系列。

优点:代码更加灵活和可维护,当需要增加新的产品对象系列时,只需要增加一个具体的工厂子类,无需修改原有代码。

缺点:实现复杂,不适合简单的应用场景。对开闭原则的支持也有一定的局限性,当需要增加新的产品对象种类时,需要修改抽象工厂和所有具体工厂的代码。

工厂模式的使用场景

基础使用:

  • 当对象创建涉及多步骤及依赖关系,工厂模式可封装复杂创建逻辑,让调用方代码更简洁。
  • 需根据不同条件创建不同类型对象,工厂模式能动态确定创建逻辑。
  • 期望统一管理对象创建以利维护和扩展,工厂模式可集中处理创建过程。

高级使用:

  • 与其他模式混用,如工厂模式与策略模式结合,或工厂模式、策略模式、模板模式共同使用。

工厂模式的优点

一、解耦

  • 工厂模式将对象的创建和使用分离,使得代码的各个部分之间的耦合度降低。使用者无需了解对象的具体创建过程,只需要从工厂获取所需的对象即可。这样,当对象的创建逻辑发生变化时,不会影响到使用对象的代码部分。
  • 例如,在一个电商系统中,订单模块需要使用支付对象进行支付操作。如果不使用工厂模式,订单模块可能直接实例化支付对象,这样订单模块就与具体的支付对象创建过程紧密耦合。当支付方式发生变化时,订单模块的代码需要进行相应的修改。而使用工厂模式,订单模块只需要从支付工厂获取支付对象,无需关心支付对象的具体创建过程,从而实现了解耦。

二、代码复用

  • 工厂类可以被多个地方复用,提高了代码的复用性。工厂类通常封装了对象的创建逻辑,可以根据不同的条件创建不同类型的对象。这些创建逻辑可以在多个地方重复使用,避免了代码的重复编写。
  • 例如,在一个图形绘制系统中,有多种不同类型的图形(圆形、矩形、三角形等)需要创建。可以创建一个图形工厂类,该工厂类可以根据不同的参数创建不同类型的图形对象。这样,在多个绘图模块中都可以复用这个图形工厂类,提高了代码的复用性。

三、符合迪米特法则和单一职责原则

  • 迪米特法则也称为最少知识原则,它强调一个对象应该对其他对象有尽可能少的了解。工厂模式将对象的创建逻辑封装在工厂类中,使用者只需要与工厂类进行交互,无需了解对象的具体创建过程,符合迪米特法则。
  • 单一职责原则要求一个类应该只有一个引起它变化的原因。工厂类的职责就是创建对象,它将对象的创建逻辑集中在一个地方,使得代码的职责更加清晰,符合单一职责原则。
  • 例如,在一个企业管理系统中,员工对象的创建可能涉及到从数据库中读取员工信息、验证员工数据的合法性等复杂的操作。如果将这些创建逻辑分散在各个使用员工对象的模块中,会导致代码的职责不清晰,违反单一职责原则。而使用工厂模式,将员工对象的创建逻辑封装在员工工厂类中,使得代码的职责更加清晰,符合单一职责原则。

简单工厂模式实现

以下是一个用于创建不同类型的手机。

一、定义手机产品接口

/**
 * 手机接口
 */
public interface Phone {
    void call();

    void sendMessage();
}

二、创建具体手机产品类

/**
 * 安卓手机
 */
public class AndroidPhone implements Phone {
    @Override
    public void call() {
        System.out.println("Android手机正在通话。");
    }

    @Override
    public void sendMessage() {
        System.out.println("Android手机正在发送消息。");
    }
}


/**
 * 苹果手机
 */
public class IPhone implements Phone {
    @Override
    public void call() {
        System.out.println("iPhone正在通话。");
    }

    @Override
    public void sendMessage() {
        System.out.println("iPhone正在发送消息。");
    }
}

三、创建简单工厂类

public class SimplePhoneFactory {
    /**
     * 根据传入的手机类型决定创建哪种具体的手机对象
     */
    public static Phone createPhone(String phoneType) {
        if ("android".equals(phoneType)) {
            return new AndroidPhone();
        } else if ("iphone".equals(phoneType)) {
            return new IPhone();
        } else {
            return null;
        }
    }
}

四、使用简单工厂-测试

public class SimpleFactoryTest {
    public static void main(String[] args) {
        Phone androidPhone = SimplePhoneFactory.createPhone("android");
        if (androidPhone != null) {
            androidPhone.call();
            androidPhone.sendMessage();
        }
        System.out.println("--------------------------------");
        Phone iPhone = SimplePhoneFactory.createPhone("iphone");
        if (iPhone != null) {
            iPhone.call();
            iPhone.sendMessage();
        }
    }
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
--------------------------------
iPhone正在通话。
iPhone正在发送消息。

总结

简单工厂模式成功地实现了手机的创建与使用之间的解耦。这使得使用者无需操心手机具体的创建流程,仅需从工厂获取所需的手机即可。然而,此模式存有一定弊端。后续若要增添新的手机类型,就必须持续地对工厂类进行修改,如此一来,维护成本便会相对较高。在简单工厂模式里,需依据方法的输入,编写大量的 if-else 语句来判断并创建不同的对象。

工厂方法模式实现

工厂方法模式可视为简单工厂模式的升级版。它针对简单工厂模式在扩展时需改动工厂代码的缺点,对工厂类进行了优化改进。通过这种方式,工厂方法模式有效地解决了简单工厂模式在扩展性方面的不足。

例子还是使用上面的Phone,实现方法如下。

一、定义手机产品接口

代码和简单工厂模式一样。

二、创建具体手机产品类

代码和简单工厂模式一样。

三、定义抽象工厂接口

public interface PhoneFactory {
    Phone createPhone();
}

四、创建具体工厂类

public class AndroidPhoneFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new AndroidPhone();
    }
}

public class IPhoneFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new IPhone();
    }
}

五、使用工厂方法模式

public class FactoryMethodTest {
    public static void main(String[] args) {
        PhoneFactory androidPhoneFactory = new AndroidPhoneFactory();
        Phone androidPhone = androidPhoneFactory.createPhone();
        androidPhone.call();
        androidPhone.sendMessage();
        System.out.println("--------------------------------");
        PhoneFactory iPhoneFactory = new IPhoneFactory();
        Phone iphone = iPhoneFactory.createPhone();
        iphone.call();
        iphone.sendMessage();
    }
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
--------------------------------
iPhone正在通话。
iPhone正在发送消息。

总结

其结果与简单工厂模式相同。二者的主要区别在于:简单工厂模式仅有一个工厂类,负责创建所有产品对象;而工厂方法模式则演变为多个工厂,每个工厂对应一种特定的产品创建。这样一来,后续扩展时只需实现工厂接口即可创建新的产品对象。然而,该模式的缺点是随着产品种类的增加,工厂类的数量也会越来越多。

抽象工厂模式实现

抽象工厂模式可视为工厂方法模式的一种扩展。该模式主要用于解决一类产品的创建问题。在抽象工厂模式中,工厂类的职责并非创建具体的单一产品对象,而是负责创建一系列相关的产品对象。例如,在某些场景下,工厂不仅要创建手机,还需创建与之对应的手机配件。对比工厂方法模式,最直观的区别在于工厂方法模式中的PhoneFactory接口通常只有一个创建手机的方法,而抽象工厂模式的AbstractPhoneFactory接口则拥有多个方法,分别用于创建不同的相关产品对象。

下面是简单画的图。

在这里插入图片描述

一、定义手机产品接口

上面有代码。

二、创建具体手机产品类

上面有代码。

三、定义手机配件接口

public class AndroidCharger implements PhoneAccessory {
    @Override
    public void describe() {
        System.out.println("安卓充电器。");
    }
}

public class IPhoneCharger implements PhoneAccessory {
    @Override
    public void describe() {
        System.out.println("苹果充电器。");
    }
}

五、定义抽象工厂接口

public interface AbstractPhoneFactory {
    /**
     * 创建手机
     */
    Phone createPhone();

    /**
     * 创建配件
     */
    PhoneAccessory createAccessory();
}

六、创建具体工厂类

public class AndroidFactory implements AbstractPhoneFactory {

    @Override
    public Phone createPhone() {
        return new AndroidPhone();
    }

    @Override
    public PhoneAccessory createAccessory() {
        return new AndroidCharger();
    }
}


public class IPhoneFactory implements AbstractPhoneFactory {
    @Override
    public Phone createPhone() {
        return new IPhone();
    }

    @Override
    public PhoneAccessory createAccessory() {
        return new IPhoneCharger();
    }
}

七、使用抽象工厂模式

public class AbstractFactoryTest {
    public static void main(String[] args) {
        AbstractPhoneFactory androidFactory = new AndroidFactory();
        Phone android = androidFactory.createPhone();
        PhoneAccessory androidAccessory = androidFactory.createAccessory();
        android.call();
        android.sendMessage();
        androidAccessory.describe();
        System.out.println("----------------------------------");
        AbstractPhoneFactory iPhoneFactory = new IPhoneFactory();
        Phone iphone = iPhoneFactory.createPhone();
        PhoneAccessory iphoneAccessory = iPhoneFactory.createAccessory();
        iphone.call();
        iphone.sendMessage();
        iphoneAccessory.describe();
    }
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
安卓充电器。
----------------------------------
iPhone正在通话。
iPhone正在发送消息。
苹果充电器。

总结

在抽象工厂模式中,可存在多个方法用于创建同品类的不同对象。然而,该模式存在一定的缺点,即当需要增加新的品类时,需要对所有的具体工厂实现类进行修改。例如,若在抽象工厂接口AbstractFactory中新增一个方法B,那么AndroidFactoryIPhoneFactory等具体工厂类都需要实现这个新增的方法B

在抽象工厂模式中,可以将上述示例中的工厂替换为工作中实际会用到的对象,例如对象存储服务(OSS)。以下展示的仅仅是两个 OSS 工厂,而在实际应用中,可能需要对接众多的 OSS 服务提供商,以满足不同的业务需求。
在这里插入图片描述

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值