写点什么

03 设计模式之工厂模式

发布于: 18 分钟前
03 设计模式之工厂模式

我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的 JavaLib」第一时间阅读最新文章,回复【资料】,即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板。

1 背景

在 Java 中,提倡面向接口编程,接口可以定义约束实现类的行为,外部调用通过接口进行调用,达到了封装隔离的效果,外部不知道内部的具实现。而且使用接口编程,提高了可维护性和可扩展性。


package com.chenpi.simplefactory;
/** * @Description * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class ChenPiMain {
public static void main(String[] args) { PayService payService = new AliPayService(); payService.pay(); }
}
interface PayService {
void pay();}
class AliPayService implements PayService {
@Override public void pay() { System.out.println("使用支付宝支付..."); }}
复制代码


以上代码其实有问题的,本来是要面向接口编程,但是客户端却知道了接口实现类,违背了封装隔离原则。那就不要让客户端去创建具体实现类,那接口实现类又该如何获取呢?

2 工厂模式

工厂模式可以解决以上问题。工厂模式属于创建型模式,它提供了一个创建对象实例的功能,而不关心其具体的实现。


工厂模式主要有工厂方法模式,抽象工厂模式两类。

2.1 工厂方法(Factory Method)

定义一个用于创建对象的接口,接口实现类决定创建哪一个类的实例,工厂方法使一个类的实例化延迟到接口的实现子类上。


工厂方法模式的结构图如下:


  • Product:定义工厂方法所创建的对象的接口。

  • ConcreteProduct:Product 接口的实现类。

  • XXFactory:工厂抽象类,里面定义一个抽象方法,返回被创建的对象的接口。

  • ConcreteXXFactory:工厂抽象方法的实现类,负责工厂方法的实例创建。



还是以开头的例子演示,工厂方法创建的实例一般都有共同的父亲,所以需要定义一个接口。


package com.chenpi.factorymethod;
/** * @Description 被创建实例的接口 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public interface PayService {
void pay();}
复制代码


再定义接口的实现类,也就是工厂实际创建的对象。


package com.chenpi.factorymethod;
/** * @Description 被创建实例接口的实现类 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class AliPayService implements PayService {
@Override public void pay() { System.out.println("使用支付宝支付..."); }}
复制代码


工厂抽象类,定义约束了需要创建的对象接口,具体实现由子类负责。工厂类的名称一般为模块名称+Factory


package com.chenpi.factorymethod;
/** * @Description 工厂抽象类 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public abstract class PayServiceFactory {
public abstract PayService getPayService();}
复制代码


工厂接口的实现类,负责创建实际需要的对象实例。


package com.chenpi.factorymethod;
/** * @Description 工厂接口实现类 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class AliPayServiceFactory extends PayServiceFactory {
@Override public PayService getPayService() { return new AliPayService(); }}
复制代码


客户端使用工厂获取对象,进行使用。


package com.chenpi.factorymethod;
/** * @Description * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class ChenPiClient {
public static void main(String[] args) { PayServiceFactory factory = new AliPayServiceFactory(); PayService payService = factory.getPayService(); payService.pay(); }}
// 输出结果使用支付宝支付...
复制代码


如果此时又要新增一个支付方式,例如微信支付,那么只需要新增一个微信支付相关的业务类,以及对象的工厂实现类即可。


package com.chenpi.factorymethod;
/** * @Description 被创建实例接口的实现类 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class WeChatPayService implements PayService {
@Override public void pay() { System.out.println("使用微信支付..."); }}
复制代码


package com.chenpi.factorymethod;
/** * @Description 工厂接口实现类 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class WeChatPayServiceFactory extends PayServiceFactory {
@Override public PayService getPayService() { return new WeChatPayService(); }}
复制代码


客户端只需要更好具体的工厂实现类即可。


package com.chenpi.factorymethod;
/** * @Description * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class ChenPiClient {
public static void main(String[] args) { PayServiceFactory factory = new WeChatPayServiceFactory(); PayService payService = factory.getPayService(); payService.pay(); }}
// 输出结果使用微信支付...
复制代码


当然这些结构不一定都是定死的,设计模式表达的是一种思想,思路,具体的落地方案都是得根据实际情况而定的,比如工厂方法模式不一定要定义工厂接口以及多个实现类,也可以直接定义一个工厂具体类,根据客户端传入的参数或者读取其他数据(例如配置文件,数据库等)选择创建具体的实例即可。


package com.chenpi.factorymethod;
/** * @Description 工厂方法 * @Author 陈皮 * @Date 2021/8/1 * @Version 1.0 */public class OnlinePayServiceFactory {
public PayService getPayService(String type) { if ("AliPay".equals(type)) { return new AliPayService(); } else if ("WeChatPay".equals(type)) { return new WeChatPayService(); } return null; }}
复制代码

2.2 抽象工厂(Abstract Factory)

工厂方法一般是创建单个类的实例,或者没有内在联系的类的实例。而且抽象工厂一般是创建有关联,或者相互依赖的类的实例,可以理解为生产产品簇的工厂。


抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的实现类。


  • AbstractFactory:抽象工厂,定义约束创建一系列产品对象的操作接口。

  • ConcreteFactory:抽象工厂的具体实现类,负责一系列有相互关系的类的对象的创建。

  • AbstractProduct:定义一系列产品对象的接口。

  • ConcreteProduct:产品接口的具体实现类。



举个例子,假如你要开个电脑组装公司,业务是帮一些电脑小白组装电脑,为简单方便讲解,我们假设组装一个电脑只需要 CPU,显示屏以及主板。那组装总公司(抽象工厂)定义约束了组装一个电脑需要哪些组件接口(一系列对象接口),但是具体牌子的电脑组件由不同的子公司(接口实现类)来实现,而且这些组件是有互相依赖关系的。总而言之,抽象工厂就是起到一个定义约束的作用,实现子类必须要接口定义来创建一系列对象。


首先定义一个抽象工厂接口,在里面定义约束创建一系列电脑组件的接口。


package com.chenpi.abstractfactory;
/** * @Description 抽象工厂 * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public interface AbstractFactory {
CPU getCPU();
Mainboard getMainboard();}
复制代码


再定义抽象工厂接口的实现类,也就是具体的组装电脑方案实现。


package com.chenpi.abstractfactory;
/** * @Description 抽象工厂实现类A * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteFactoryA implements AbstractFactory {
@Override public CPU getCPU() { return new ConcreteCPUA(); }
@Override public Mainboard getMainboard() { return new ConcreteMainboardA(); }}
复制代码


package com.chenpi.abstractfactory;
/** * @Description 抽象工厂实现类B * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteFactoryB implements AbstractFactory {
@Override public CPU getCPU() { return new ConcreteCPUB(); }
@Override public Mainboard getMainboard() { return new ConcreteMainboardB(); }}
复制代码


CPU 产品接口定义,以及 CPU 具体实现类定义。


package com.chenpi.abstractfactory;
/** * @Description 抽象CPU接口 * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public interface CPU {
}
复制代码


package com.chenpi.abstractfactory;
/** * @Description 具体品牌A的CPU * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteCPUA implements CPU {
}
复制代码


package com.chenpi.abstractfactory;
/** * @Description 具体品牌B的CPU * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteCPUB implements CPU {
}
复制代码


主板产品接口定义,以及主板接口的具体实现类定义。


package com.chenpi.abstractfactory;
/** * @Description 抽象主板接口 * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public interface Mainboard {
}
复制代码


package com.chenpi.abstractfactory;
/** * @Description 品牌A的主板 * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteMainboardA implements Mainboard {
}
复制代码


package com.chenpi.abstractfactory;
/** * @Description 品牌B的主板 * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class ConcreteMainboardB implements Mainboard {
}
复制代码


编写客户端,进行验证,假设选择方案 A 进行验证。


package com.chenpi.abstractfactory;
/** * @Description * @Author 陈皮 * @Date 2021/8/3 * @Version 1.0 */public class Client {
public static void main(String[] args) { AbstractFactory factory = new ConcreteFactoryA(); CPU cpu = factory.getCPU(); Mainboard mainboard = factory.getMainboard();
System.out.println("CPU:" + cpu); System.out.println("Mainboard:" + mainboard); }}
// 输出结果CPU:com.chenpi.abstractfactory.ConcreteCPUA@4554617cMainboard:com.chenpi.abstractfactory.ConcreteMainboardA@74a14482
复制代码


通过抽象工厂模式,确保了一个具体的工厂只生产有互相关联,互相依赖的产品簇,不会出现混乱搭配的情况。




本次分享到此结束啦~~


如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

发布于: 18 分钟前阅读数: 6
用户头像

CSDN博客专家,微信搜一搜 - 陈皮的JavaLib 2020.02.22 加入

CSDN博客专家,专注各项技术领域的Java开发工程师,微信搜一搜【陈皮的JavaLib】,关注后学习更多技术文章和一线大厂面试资料和技术电子书籍。

评论

发布
暂无评论
03 设计模式之工厂模式