我是陈皮,一个在互联网 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@4554617c
Mainboard:com.chenpi.abstractfactory.ConcreteMainboardA@74a14482
复制代码
通过抽象工厂模式,确保了一个具体的工厂只生产有互相关联,互相依赖的产品簇,不会出现混乱搭配的情况。
本次分享到此结束啦~~
如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!
评论