Java设计模式之工厂模式

介绍

简单工厂模式是属于创建型模式,又叫做静态工厂方法模式。

它的实现方式是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

简单工厂模式由三种角色组成:

  1. 工厂角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
  2. 抽象产品角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  3. 具体产品角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

问题

在软件设计中,我们经常遇到需要创建不同类型对象的情况。但是,如果直接在代码中实例化对象,会使代码紧密耦合在一起,难以维护和扩展。此外,如果对象的创建方式需要变化,那么就需要在整个代码中进行大量的修改。工厂方法模式旨在解决这个问题。

解决方案

工厂方法模式提供了一个创建对象的接口,但是将具体的对象创建延迟到子类中。这样,客户端代码不需要知道要创建的具体对象的类,只需要通过工厂方法来创建对象。这使得客户端代码与具体对象的创建解耦,提高了代码的灵活性和可维护性。

在工厂方法模式中,通常会定义一个抽象工厂类,其中包含一个创建对象的抽象方法,而具体的对象创建则由具体的子类实现。这样,每个具体的子类都可以根据需要创建不同类型的对象,而客户端代码只需要通过抽象工厂类来调用工厂方法,而不需要关心具体的对象创建细节。

效果

工厂方法模式的优点包括:

  • 松耦合:客户端代码与具体对象的创建解耦,使得系统更具弹性和可维护性。
  • 扩展性:通过添加新的具体工厂和产品子类,可以很容易地扩展系统以支持新的对象类型。
  • 封装性:将对象的创建集中在工厂类中,封装了对象的创建细节,使得客户端代码更简洁。

然而,工厂方法模式也可能引入一些额外的复杂性,因为需要定义多个工厂类和产品类的层次结构。这可能会导致系统中类的数量增加。在选择使用工厂方法模式时,需要根据具体情况进行权衡。

工厂方法模式在实际应用中非常常见,例如,图形库可以使用工厂方法模式来创建不同类型的图形对象,数据库访问框架可以使用工厂方法模式来创建不同类型的数据库连接等。

普通工厂模式

定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂模式使一个类的实例化延迟到其子类。

java 复制代码
abstract class Animal {
    public abstract void sound();
}
class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("喵喵喵");
    }
}
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
}
// 创建一个工厂类
class AnimalFactory {
    // 定义一个静态方法,根据传入的参数创建具体的产品类对象
    public static Animal createAnimal(String type) {
        if (type.equalsIgnoreCase("dog")) {
            return new Dog();
        } else if (type.equalsIgnoreCase("cat")) {
            return new Cat();
        } else {
            throw new IllegalArgumentException("Invalid animal type: " + type);
        }
    }
}
// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 使用工厂类创建不同的 Animal 对象
        Animal dog = AnimalFactory.createAnimal("dog");
        dog.sound();
        Animal cat = AnimalFactory.createAnimal("cat");
        cat.sound();
    }
}

抽象工厂模式

提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。

通过定义一个创建对象的接口来创建对象,但将具体实现的决定留给子类来决定。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

java 复制代码
// 创建一个抽象产品类
abstract class Animal {
    public abstract void sound();
}
class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("喵喵喵");
    }
}
// 创建具体产品类,继承自 Animal 类
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
}

abstract class AnimalFactory {
    // 定义一个抽象方法,用于创建 Animal 对象
    public abstract Animal createAnimal();
}
class CatFactory extends AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
// 创建具体工厂类,实现创建 Animal 对象的接口
class DogFactory extends AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 创建一个 Dog 对象
        AnimalFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.sound();

        // 创建一个 Cat 对象
        AnimalFactory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.sound();
    }
}

应用场景

  • 当需要创建对象的过程比较复杂,需要进行复杂的初始化或依赖注入时,可以使用工厂模式来封装这个过程,简化客户端代码。
  • 当需要创建多个对象具有相似功能或共享一些相同属性时,可以使用工厂模式来创建这些对象,从而使代码更加简洁和易于维护。

需要注意的是,虽然工厂模式可以提高代码的灵活性和可维护性,但是如果工厂的创建过程非常复杂,可能会影响系统的性能。此时需要权衡设计的复杂度和系统的性能要求,选择合适的创建方式。

具体场景

商城支付场景

在一个商城系统中,用户可以选择三种支付方式,微信支付,支付宝支付,余额支付。

我们将创建一个 PaymentMethod 接口和实现 PaymentMethod 接口的实体类。下一步是定义工厂类 PayFactory。

Main是演示我们简单工厂模式的入口。

UML图如下:

java 复制代码
 步骤1.创建接口类

public interface PaymentMethod {
    void pay();
}
步骤2.实现接口类

public class Alipay implements PaymentMethod {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}
public class BalancePay implements PaymentMethod {
    @Override
    public void pay() {
        System.out.println("余额支付");
    }
}
public class WechatPay implements PaymentMethod {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}
步骤3.创建一个工厂,生成基于给定信息的实体类的对象。

public class PayFactory {

    public PaymentMethod getPayment(String payType){

        switch (payType){

            case "alipay":
                return new Alipay();
            case "wechatPay":
                return new WechatPay();
            case "balancePay":
                return new BalancePay();

            default:
                System.out.println("支付方式错误");

        }
        return null;

    }

}
步骤4.使用该工厂,通过传递类型信息来获取实体类的对象。

public class Main {

    public static void main(String[] args) {

        PayFactory payFactory = new PayFactory();

        PaymentMethod paymentMethod = payFactory.getPayment("alipay");

        paymentMethod.pay();

    }

}
相关推荐
weixin_307779135 小时前
使用Python高效读取ZIP压缩文件中的UTF-8 JSON数据到Pandas和PySpark DataFrame
开发语言·python·算法·自动化·json
哎呀呦呵5 小时前
python内置模块-re模块介绍使用
java·python·mysql
louisgeek5 小时前
Java CompletableFuture
java
ะัี潪ิื5 小时前
精灵图(雪碧图)的生成和使用
java·css
web安全工具库5 小时前
从课堂笔记到实践:深入理解Linux C函数库的奥秘
java·数据库·算法
ss2735 小时前
手写MyBatis第104弹:SqlSession从工厂构建到执行器选择的深度剖析
java·开发语言·后端·mybatis
周杰伦_Jay6 小时前
【Java集合体系】全面解析:架构、原理与实战选型
java·开发语言·数据结构·链表·架构
Camel卡蒙6 小时前
DDD架构——实体、聚合、值对象
java·开发语言·架构
青云交6 小时前
Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式电源接入与电力系统稳定性维护中的应用
java·分布式电源·智能电网·java 大数据·flink 实时流处理·kafka 数据采集·iec 61850 协议