概念定义

简单工厂(Simple Factory)模式,又称静态工厂方法(Static Factory Method)模式,即定义一个工厂类,根据传入的不同参数创建不同的产品实例,这些实例对象具有共同的父类或接口。

应用场景

  • 需要创建的产品对象较少,否则工厂逻辑会过于复杂。
  • 客户端只关心产品的接口,而不关心对象的具体创建过程。

示例代码

简单工厂模式由一个工厂类、一个产品接口(或抽象类)和一组实现该接口的具体产品组成。这个工厂类根据传入的参数创造一个具体的产品实现类,并向上转型为接口作为结果返回。

本节通过一个"喜闻乐见"的豪车系列,展示简单工厂模式的实现。示例代码如下:

// 产品接口 //
public interface ICar { // 抽象类无法多重继承,而接口支持多实现,扩展性更好
void drive();
}
// 若干具体的产品 //
public class Bmw implements ICar {
@Override
public void drive() { System.out.println("drive a Bmw"); }
}
public class Benz implements ICar {
@Override
public void drive() { System.out.println("drive a Benz"); }
}
public class Audi implements ICar {
@Override
public void drive() { System.out.println("drive a Audi"); }
}
// 工厂类 //
public class SimpleFactory {
private SimpleFactory() {}
public static ICar create(String car) { // 工厂不需要有状态,因此创造产品的方法是静态的
if ("Bmw".equalsIgnoreCase(car)) {
return new Bmw(); // 后续可在工厂里变更产品类名、构造方法参数甚至实例化方式
} else if ("Benz".equalsIgnoreCase(car)) {
return new Benz();
} else if("Audi".equalsIgnoreCase(car)) {
return new Audi();
} else {
return null;
}
}
}

客户端通过SimpleFactory.create("BMW").drive()即可创建Bmw实例并调用其drive()方法。

如注释所示,工厂类封装了产品对象的创建过程,从而可在客户端不感知的情况下修改产品的创建方式。例如,若产品类实现了Cloneable接口,就可以在工厂中用(ICar)Bmw.clone()替代new Bmw()

此外,还可以通过枚举甚至注解实现简单工厂模式。以枚举实现为例:

public enum EnumCarFactory {
BMW {
@Override
public ICar create() { return new Bmw(); }
},
BENZ {
@Override
public ICar create() { return new Benz(); }
},
AUDI {
@Override
public ICar create() { return new Audi(); }
}; public abstract ICar create(); // abstract修饰方法,强制每个枚举实现该方法
}

客户端通过EnumCarFactory.AUDI.create().drive()EnumCarFactory.valueOf("AUDI").create().drive(),即可创建Audi实例并调用其draw()方法。

注意,以上实现并不符合开放-封闭原则(对扩展开放,对修改关闭)。例如新增产品时,SimpleFactory工厂内需要添加分支条件,EnumCarFactory工厂内则要添加对应的枚举定义。这一缺陷可以通过反射机制来避免:

public class EnhancedSimpleFactory {
private EnhancedSimpleFactory() {}
public static <T> T create(Class<? extends T> clazz) {
T obj = null;
try {
obj = (T) Class.forName(clazz.getName()).newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
}

客户端通过EnhancedSimpleFactory.create(Benz.class).drive(),即可创建Benz实例并调用其draw()方法。

注意,EnhancedSimpleFactory.create(clazz)的入参类路径也可来自配置文件、数据库等,因此更具灵活性。

模式优缺点

简单工厂模式的优点如下:

  • 解耦:将对象的创建和使用过程分开(客户端只接触产品接口),降低对象和客户端的耦合关系。
  • 降低代码重复: 将创建对象的过程集中于工厂内部,当创建对象较为复杂且频繁创建时,可以减少重复性代码。
  • 降低维护成本:创建过程由工厂统一管理,当业务逻辑变更时在工厂里修改即可,而无需逐个修正所有需要创建对象的地方。

缺点如下:

  • 简单工厂使用静态工厂方法,静态方法不能被继承和重写,因此工厂角色无法形成基于继承的等级结构。
  • 简单工厂容易违背开放-封闭原则(虽然可以通过反射机制改善),可能导致工厂逻辑过于复杂。
  • 工厂类集中负责所有产品对象的创建逻辑,一旦工厂不能正常工作,整个系统都会受到影响。

业界实践

随处可见……

Java设计模式:Simple Factory(简单工厂)模式的更多相关文章

  1. Simple Factory (简单工厂模式)

    简单工厂模式不是23种设计模式之一,简单工厂模式属于创建型模式, 又叫做静态工厂方法(Static Factory Method) 简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模 ...

  2. java设计模式-----1、简单工厂模式

    简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单来说 ...

  3. 设计模式(四):SIMPLE FACTORY简单工厂模式 -- 创建型模式

    1.定义 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口. 2.适用场景 如果一个客户要一款宝马车,一般的做法是客户去创建一款宝 ...

  4. Simple Factory 简单工厂模式(静态工厂)

    基本概念: 1) Simple Factory模式属于创建型模式, 2) 简单工厂模式是由一个工厂(注意是一个!)对象决定创建出哪一种产品类的实例(例如你到肯德基说你要鸡腿,要薯条,要饮料还是,,,这 ...

  5. Java设计模式学习记录-简单工厂模式、工厂方法模式

    前言 之前介绍了设计模式的原则和分类等概述.今天开启设计模式的学习,首先要介绍的就是工厂模式,在介绍工厂模式前会先介绍一下简单工厂模式,这样由浅入深来介绍. 简单工厂模式 做法:创建一个工厂(方法或类 ...

  6. Java设计模式2:简单工厂模式

    简单工厂模式 简单工厂模式是类的创建模式,又叫做静态工厂方法模式.简单工厂模式由一个工厂对象决定生产出哪一种产品类的实例. 为什么要使用简单工厂模式 原因很简单:解耦. A对象如果要调用B对象,最简单 ...

  7. JAVA设计模式之【简单工厂模式】

    1.创建抽象类User public abstract class User // 抽象类 { public void sameOperation() { System.out.println(&qu ...

  8. Net设计模式实例之简单工厂模式(Simple Factory Pattern)

    一.简单工厂模式简介(Bref Introduction) 简单工厂模式(Simple Factory Pattern)的优点是,工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类, ...

  9. Java设计模式(1)工厂模式(Factory模式)

    工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...

随机推荐

  1. MQ脚本回放报错2059

    1.响应2059错误 1.1.   涉及协议 MQ,调试回放阶段 1.2.   错误信息 完成码2原因为2059:未能为 '10.200.100.75:QMEMBFE' 创建 MQQueueManag ...

  2. C 语言输出不同颜色字体

    C 语言输出不同颜色字体 \033是8进制,它就是unix下终端转义符ESC(16进制1A,10进制27) ESC[xm 是unix下改变终端输出颜色的命令 所以,如果是红色,则我们定义为\033[0 ...

  3. 解决RubyMine中puts中文显示乱码的问题

    一个简单的ruby代码,puts一个中文,显示乱码 # -*- coding: utf-8 -*- puts "你好" require_relative 'calc.rb' # r ...

  4. ETCD:基于角色的访问控制

    原文地址:Role-based access control 总览 身份验证已添加到etcd 2.1中. etcd v3 API略微修改了身份验证功能的API和用户界面,以更好地适应新的数据模型.本指 ...

  5. Java面试,如何在短时间内做突击

    面试前很有必要针对性的多刷题,大部分童鞋实战能力强,理论不行,面试前不做准备很吃亏.这里整理了很多常考面试题,希望对你有帮助.   面试技术文 Java岗 面试考点精讲(基础篇01期) Java岗 面 ...

  6. python-Redis模块常用的方法汇总

    Redes模块常用的方法汇总 一.创建建Redis对象 1.直接使用 import redis r = redis.Redis(host='127.0.0.1', port=6379) 2.连接池使用 ...

  7. 使用Navicat Premium 比较PostgreSql数据库 dev环境与test环境差异

    Navicat Premium 功能很强大,支持不同数据库客户端的连接,并且使用工具可以生成两个库差异的sql脚本,方便dev与test环境表结构同步,具体操作方法如下 单击运行,实现两个库中模式表结 ...

  8. JavaScript 语法:松软科技前端教程

    JavaScript 语法是一套规则,它定义了 JavaScript 的语言结构. var x, y; // 如何声明变量 x = 7; y = 8; // 如何赋值 z = x + y; // 如何 ...

  9. flex下省略号的问题解决

    最近在搞微信小程序,发现flex下使用省略号是没有效果的,而且还会打乱预期的结构,查询statckoverflow知道需要在父级设置min-width:0; 但是在我的尝试下,依然不行,原来在上层父级 ...

  10. Node.js操作Mysql的简单示例

    API的封装:封装为系统可用的工具,分为线上和线上的数据库. 使用:让API直接操作数据库,不再使用假数据. DEMO代码: const mysql = require('mysql'); // 创建 ...