vlambda博客
学习文章列表

《疯狂学习之Java设计模式之简单工厂模式》

《疯狂学习之Java设计模式之简单工厂模式》

目录

一、模式类型

二、模式定义

三、模式原理

1、模式组成

2、模式UML图

四、模式实际的应用

1、例子背景

2、代码验证

3、UML图

五、模式总结

1、优点

2、缺点

3、解决了哪些问题

4、应用场景

六、代码

一、模式类型

<b>简单工厂模式</b>属于<b>创建型模式</b>,但是它不属于23种设计模式中的任何一种,是工厂模式的简单化模式,又叫<b>静态工厂方法模式</b>。

二、模式定义

<b>简单工厂模式</b>:字面意思可以看出,这里会用到一个简单的工厂,现实中,我们都知道工厂是批量生成同一类不同属性的商品的地方,那么在代码中,我们拿工厂来批量创建同一类不同的对象,此时这个创建对象的类就是<b>"工厂类"</b>,<b>简单工厂模式</b>就是工厂类以一个简单的静态方法的形式,通过传递参数的不同来决定具体创建哪个具体产品对象。

三、模式原理

1、模式组成

  • 抽象产品对象

    这个类主要是将有规律的一类对象进行归类为一类,方便创建,代码如下:

    /**
    * 抽象产品
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public interface IProduct {

    /**
    * 打印产品名称
    */
    void printProductName();

    }


  • 具体产品对象

    /**
    * 具体产品A
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class ProductA implements IProduct {

    @Override
    public void printProductName() {
    System.out.println("I'm ProductA");
    }
    }

    /**
    * 具体产品B
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class ProductB implements IProduct {

    @Override
    public void printProductName() {
    System.out.println("I'm ProductB");
    }
    }

    /**
    * 具体产品C
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class ProductC implements IProduct {

    @Override
    public void printProductName() {
    System.out.println("I'm ProductC");
    }
    }


  • 产品对象工厂类

    /**
    * 抽象产品的工厂
    * 可以根据传递的参数判断来创建具体的产品
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class ProductFactory {

    public static IProduct createProduct(String params) {
    if ("A".equalsIgnoreCase(params)) {
    return new ProductA();
    } else if ("B".equalsIgnoreCase(params)) {
    return new ProductB();
    } else if ("C".equalsIgnoreCase(params)) {
    return new ProductC();
    } else {
    return null;
    }

    }
    }


  • 客户端

    /**
    * 客户端
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class Client {

    public static void main(String[] args) {
    //客户需要A产品
    IProduct productA = ProductFactory.createProduct("A");
    assert productA != null;
    try {
    productA.printProductName();
    } catch (Exception e) {
    System.out.println("您需要的产品尚未开始生产");
    }

    //客户需要B产品
    IProduct productB = ProductFactory.createProduct("B");
    assert productB != null;
    try {
    productB.printProductName();
    } catch (Exception e) {
    System.out.println("您需要的产品尚未开始生产");
    }

    //客户需要C产品
    IProduct productC = ProductFactory.createProduct("C");
    assert productC != null;
    try {
    productC.printProductName();
    } catch (Exception e) {
    System.out.println("您需要的产品尚未开始生产");
    }

    //客户需要D产品
    IProduct productD = ProductFactory.createProduct("D");
    assert productD != null;
    try {
    productD.printProductName();
    } catch (Exception e) {
    System.out.println("您需要的产品尚未开始生产");
    }

    }
    }


    客户端执行结果

    I'm ProductA
    I'm ProductB
    I'm ProductC
    您需要的产品尚未开始生产


2、模式UML图


《疯狂学习之Java设计模式之简单工厂模式》

四、模式实际应用

1、例子背景

  • 我们经常遇到的场景:登录

  • 我们现在社交百花齐放,登录的时候除了基础的用户名密码登录之外,还有手机号码验证码登录,邮箱密码登录等等。

  • 而这个背景就很符合我们的简单工厂模式,将登录事件抽象为一个产品对象,不同的登录方式的登录就是一个个的具体的登录产品,此时我们为了统一的去一个方法解决多种方式的登录问题。

2、代码验证

  • 将登录事件抽象为一个产品对象

/**
* 抽象的登录场景
*
* @author pengzhan.qian
* @since 1.0.0
*/
public interface ILogin {

/**
* 具体的登录逻辑
*/
void login();
}


  • 不同的登录方式的登录就是一个个的具体的登录产品

    /**
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class UserNameAndPasswordLogin implements ILogin {
    @Override
    public void login() {
    System.out.println("现在客户正在使用用户名和密码登录");
    }
    }

    /**
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class PhoneAndCaptchaLogin implements ILogin {
    @Override
    public void login() {
    System.out.println("现在客户正在使用手机号码验证码登录");
    }
    }

    /**
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class EmailAndPasswordLogin implements ILogin {
    @Override
    public void login() {
    System.out.println("现在客户正在使用邮箱账号和密码登录");
    }
    }


  • 工厂类就是统一方法

    /**
    * 登录工厂类
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class LoginFactory {

    /**
    * 提前定义好前端传参 loginStyle
    * loginStyle = 1 用户名密码登录
    * loginStyle = 2 邮箱密码登录
    * loginStyle = 3 手机号码验证码登录
    *
    * @param loginStyle
    * @return
    */
    public static ILogin selectLoginStyle(Integer loginStyle) {
    ILogin login = null;
    switch (loginStyle) {
    case 1:
    login = new UserNameAndPasswordLogin();
    break;
    case 2:
    login = new EmailAndPasswordLogin();
    break;
    case 3:
    login = new PhoneAndCaptchaLogin();
    break;
    default:
    System.out.println("登录方式非法");
    }
    return login;
    }
    }


  • 客户端就是登录界面

    /**
    * 客户端 类似与登录界面的请求
    *
    * @author pengzhan.qian
    * @since 1.0.0
    */
    public class Client {

    /**
    * 这里的main方法类似于接口的controller
    *
    * @param args
    */
    public static void main(String[] args) {
    //A客户使用用户名密码进行登录 前端传参数 loginStyle = 1
    ILogin loginA = LoginFactory.selectLoginStyle(1);
    try {
    loginA.login();
    } catch (Exception e) {
    System.out.println("错误的登录方式");
    }

    //B客户使用邮箱密码进行登录 前端传参数 loginStyle = 2
    ILogin loginB = LoginFactory.selectLoginStyle(2);
    try {
    loginB.login();
    } catch (Exception e) {
    System.out.println("错误的登录方式");
    }

    //C客户使用手机号码验证码进行登录 前端传参数 loginStyle = 3
    ILogin loginC = LoginFactory.selectLoginStyle(3);
    try {
    loginC.login();
    } catch (Exception e) {
    System.out.println("错误的登录方式");
    }

    //D客户使用第三方进行登录 前端传参数 loginStyle = 4
    ILogin loginD = LoginFactory.selectLoginStyle(4);
    try {
    loginD.login();
    } catch (Exception e) {
    System.out.println("错误的登录方式");
    }
    }
    }

    执行结果:
    现在客户正在使用用户名和密码登录
    现在客户正在使用邮箱账号和密码登录
    现在客户正在使用手机号码验证码登录
    登录方式非法
    错误的登录方式


3、UML图



五、模式总结

1、优点

  • 解耦:将对象的具体的创建过程对使用者进行了屏蔽,使用者只需要通过工厂类选择参数来创建不同的实例对象即可

  • 可读性和可维护性:对同一类的对象实例化,增加一个类即可,便于维护;代码也比较简洁,增加了可读性

  • 面向对象和接口编程,而不是面向实现编程

2、缺点

  • 违背了“开闭原则”,因为都是在一个工厂的方法中,修改不可避免的要改代码;

  • 简单工厂模式使用静态工厂方法,静态方法不能被继承和重写,不利于继承或者扩展;

3、解决了哪些问题

  • 将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦。

4、应用场景

  • 客户如果只知道传入工厂类的参数(交给客户界面上输入),对于如何创建对象的逻辑不关心时;

  • 当工厂类负责创建的对象(具体产品)比较少时。

  • 登录注册场景

  • 统一支付使用不同支付渠道的场景

六、代码地址

请点击跳转