什么是工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式可以分为三类:简单工厂模式(静态工厂模式)、工厂方法模式 和 抽象工厂模式。
其中简单工厂模式,严格上来说,不属于23设计模式之一,因为它违背了开闭原则,更好的是看作为一种编程方式。
本篇中会介绍三种工厂的使用,也就是
- 简单(静态)工厂模式(不属于GOF的23种经典设计模式)
- 工厂方法模式
- 抽象工厂模式
使用场景
日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
等等。。。
下面我们模拟手机工厂生产手机。。。
核心角色
- 抽象产品:定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
- 具体产品:实现了抽象产品接口,定义了具体产品的特定行为和属性。
- 抽象工厂:声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
- 具体工厂:实现了抽象工厂接口,负责实际创建具体产品的对象。
1.简单(静态)工厂模式
实现了抽象工厂接口,负责实际创建具体产品的对象。
结构
简单工厂包含如下角色:
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品:实现或者继承抽象产品的子类
- 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。
示例
模拟手机工厂生产手机。
我们需要定义一个抽象手机产品,定义手机产品的品牌和颜色两个方法
/*** 手机产品抽象类** @author jiangkd* @date 2023/7/28 14:03:15*/
public abstract class AbstractPhone {/*** 手机品牌*/public abstract void brand();/*** 手机颜色*/public abstract void color();}
然后有两个具体产品,一加和真我,哈哈哈
/*** 具体手机产品, 一加手机** @author jiangkd* @date 2023/7/28 14:06:17*/
@Slf4j
public class YijiaPhone extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 一加手机!!!");}@Overridepublic void color() {log.info("黑色!!!");}}
/*** 具体手机产品, 真我手机** @author jiangkd* @date 2023/7/28 14:07:27*/
@Slf4j
public class ZhenwoPhobe extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 真我手机!!!");}@Overridepublic void color() {log.info("白色!!!");}}
产品有了,现在我们创建一个手机工厂,可以根据不同参数创建不同品牌手机
/*** 手机产品的工厂** @author jiangkd* @date 2023/7/28 14:09:50*/
public class PhoneFactory {/*** 具体如何产生一个产品的对象,是由具体的工厂类实现的* <p>* 注意, 这里是静态方法** @param clazz* @return AbstractPhone* @throws Exception e*/public static AbstractPhone createPhone(Class clazz) throws Exception {// 全限定类名final String name = clazz.getName();// 根据反射, 创建具体产品对象return (AbstractPhone) Class.forName(name).newInstance();}/*** 当前方法其实和createPhone方法是一样的作用, 两个方法用哪个都可以* <p>* 注意, 这里是静态方法** @param brand 根据参数区分创建哪个具体产品* @return AbstractPhone*/public static AbstractPhone createPhone2(String brand) throws Exception {if (CharSequenceUtil.equals("yijia", brand)) {return new YijiaPhone();} else if (CharSequenceUtil.equals("zhenwo", brand)) {return new ZhenwoPhobe();} else {throw new Exception("参数异常!!!");}}}
测试一下
/*** @author jiangkd* @date 2023/7/28 14:17:25*/
@Slf4j
public class DemoTest {public static void main(String[] args) throws Exception {// 创建一加手机AbstractPhone yijiaPhone = PhoneFactory.createPhone(YijiaPhone.class);yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");yijiaPhone = PhoneFactory.createPhone2("yijia");yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 创建真我手机AbstractPhone zhenwoPhone = PhoneFactory.createPhone(ZhenwoPhobe.class);zhenwoPhone.brand();zhenwoPhone.color();log.info("--------------------------------");zhenwoPhone = PhoneFactory.createPhone2("zhenwo");zhenwoPhone.brand();zhenwoPhone.color();}}
运行结果如下:
14:19:59.846 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!
其实可以看出来,这里我们只有两个具体的手机产品,简答(静态)工厂模式还是很方便的,但你有没有发现,如果现在我陆陆续续追加其他具体产品 红米!努比亚!荣耀!那么我就要陆陆续续三次修改手机工厂类(追加具体产品不算修改,是扩展功能)的功能,这显然不符合java设计模式的六大原则-开闭原则。
那不如我们把工厂拆开,每个工厂只生产一种具体的手机产品,这样如果我需要增加一个红米,就只需要添加一个红米工厂和一个红米产品类就可以了,这就是接下来要演示的工厂方法模式
2.工厂方法模式
简单工厂模式确实很方便,但是每次新增一个手机产品都需要改动整个工厂的原有代码,现在使用工厂方法模式改造一下。
抽象手机产品AbstractPhone 和 两个具体的手机产品(一加,真我)不变,依然如上。
工厂类PhoneFactory不要了,我们需要重新创建工厂类。
现在我们首先创建一个抽象工厂类,用来生产AbstractPhone
/*** 定义产品的抽象工厂类** @author jiangkd* @date 2023/7/28 14:43:04*/
public abstract class AbstractPhoneFactory {/*** 构建产品, 具体实现交给子类** @return AbstractPhone*/abstract AbstractPhone createPhone();}
然后分别是一加手机和真我手机的两个具体工厂实现类,每个实现类针对一个具体手机品牌的生产
/*** 具体产品一加手机的工厂实现类** @author jiangkd* @date 2023/7/28 14:44:53*/
public class YijiaPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new YijiaPhone();}}
/*** 具体产品真我手机的工厂实现类** @author jiangkd* @date 2023/7/28 14:45:35*/
public class ZhenwoPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new ZhenwoPhobe();}}
测试一下
/*** @author jiangkd* @date 2023/7/28 14:46:16*/
@Slf4j
public class DemoTest {public static void main(String[] args) {// 生产一加手机final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 生产真我手机final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();zhenwoPhone.brand();zhenwoPhone.color();}}
运行结果如下:
14:48:22.596 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!
现在我们如果想要加一个红米手机,只需要创建具体红米产品和对应的工厂类就可以了
/*** 具体手机产品 红米** @author jiangkd* @date 2023/7/28 14:51:09*/
@Slf4j
public class HongmiPhone extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 红米手机!!!");}@Overridepublic void color() {log.info("红色!!!");}}
/*** 红米手机工厂实现类** @author jiangkd* @date 2023/7/28 14:52:04*/
public class HongmiPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new HongmiPhone();}}
测试
/*** @author jiangkd* @date 2023/7/28 14:46:16*/
@Slf4j
public class DemoTest {public static void main(String[] args) {// 生产一加手机final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 生产真我手机final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();zhenwoPhone.brand();zhenwoPhone.color();log.info("--------------------------------");// 生产红米手机final AbstractPhoneFactory hongmiPhoneFactory = new HongmiPhoneFactory();final AbstractPhone hongmiPhone = hongmiPhoneFactory.createPhone();hongmiPhone.brand();hongmiPhone.color();}}
执行结果
14:53:43.272 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 品牌, 红米手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 红色!!!
符合开闭原则,不修改原来的功能,只是添加产品和工厂类就可以了。
细心的小伙伴又会问了,虽然不用在原基础功能上修改,但是如果还要添加10个品牌手机,岂不是要加10个产品类和10个工厂类,增加维护难度呀!是的,这就是工厂方法模式的弊端,增加系统的复杂度。
所以你可以看出,简单(静态)工厂和工厂方法模式,都是针对一类产品的生产,也就是这些工厂只生产同种类产品,同种类产品称为同等级产品。(工厂方法模式只考虑生产同等级的产品)
但实际上呢,现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
这就是下面的抽象工厂模式了。。。,我们继续延申,现在老板发话了,生产手机的时候,顺便把耳机也生产出来吧
3.抽象工厂模式
由于篇幅问题,继续查看java设计模式-工厂模式(下)