工厂模式(Factory Pattern):Java 中最常用的设计模式之一,是用工厂方法代替new操作的一种模式。该模式用于封装和管理对象的创建,是一种创建型模式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。这样可以让调用者不再过多关心对象创建的逻辑。
场景示例
在下面的情况下应当考虑使用工厂模式来创建实例:
- 在编码时不能预见需要创建哪种类的实例;
- 系统不应依赖于产品类实例如何被创建、组合和表达的细节;
代码示例
下面我们根据需求场景分别做举例。
简单工厂模式
假设商城中在订单下单时需要检查库存信息,但是每个商家的库存验证规则不一样,同时它们的创建很简单,此时我们可以根据不同类型来基于工厂模式实现对象的创建。
这种模式也称为静态工厂模式,通过一个方法来根据需要创建对应的实例;这样的好处是当需要更改相关的初始化信息时只需要对工厂类进行修改即可。
定义工厂
public static class PhoneServiceFactory {
public static PhoneService create(int type) {
// 根据类型创建不同的实现类
if(type==0){
return new HuaWeiPhoneServiceImpl();
}
return new IPhoneServiceImpl();
}
}
库存校验的接口实现类
public interface PhoneService {
/**
* 库存检验
*/
void stockCheck();
}
public static class HuaWeiPhoneServiceImpl implements PhoneService {
@Override
public void stockCheck() {
System.out.println("华为手机:由于芯片问题,手机库存可能不足,请帮到想哈办法");
}
}
public static class IPhoneServiceImpl implements PhoneService {
@Override
public void stockCheck() {
System.out.println("苹果手机:库存基本充足");
}
}
调用
PhoneService phoneService = PhoneServiceFactory.create(0);
phoneService.stockCheck();
phoneService = PhoneServiceFactory.create(1);
phoneService.stockCheck();
工厂方法模式
提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类,并且由该实现类创建对应类的实例。即提供一个工厂接口,其他工厂实现这个接口中的创建方法,相当于工厂类增加了一个工厂接口(或抽象类)。
作用
这种模式其实就是为解决有多个简单工厂模式的工厂类(这些工厂类创建的实例相同,但是创建的时候会有不同实现,或者是有一些公共的配置信息)。
- 可以一定程度上解耦,消费者和提供者实现类隔离开,只依赖提供者接口(抽象类),提供者实现类如何改动与消费者完全无关。
- 可以一定程度增加扩展性,若增加一个提供者实现,只需要实现提供者接口,修改工厂创建提供者的方法,消费者可以无感知(若消费者不关心具体提供者是什么的情况)。
- 可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少代码量就可以完成很多工作。
下面我们通过一个消息发送的案例来举例
通过实现抽象工厂的方法
消息发送的接口实现
public interface MessageService {
/**
* 发送消息
*/
void sendMessage();
String getParams();
String setParams(String params);
}
public static class SmsServiceImpl implements MessageService {
private String recipient;
@Override
public void sendMessage() {
System.out.println("发送短信:"+getParams());
}
@Override
public String getParams() {
return this.recipient;
}
@Override
public String setParams(String params) {
return recipient = params;
}
}
public static class EmailServiceImpl implements MessageService {
private String recipient;
@Override
public void sendMessage() {
System.out.println("发送邮件:"+getParams());
}
@Override
public String getParams() {
return this.recipient;
}
@Override
public String setParams(String params) {
return recipient = params;
}
}
定义一个抽象工厂类
public static abstract class AbstractMessageFactory {
public static MessageService createMessage(int type) {
// 公共初始信息
// TODO...
// 私有初始信息
if(type==0){
return SmsFactory.getInstance().create();
}
return EmailFactory.getInstance().create();
}
/**
* 创建对应实例;也可以定义一个工厂接口,让所有的工厂实现工厂接口的创建方法
* @return 返回实例
*/
public abstract MessageService create();
}
根据业务需要实现抽象工厂
public static class SmsFactory extends AbstractMessageFactory {
private static final SmsFactory INSTANCE = new SmsFactory();
private SmsFactory(){
}
public static SmsFactory getInstance(){
return INSTANCE;
}
@Override
public MessageService create() {
SmsServiceImpl smsService = new SmsServiceImpl();
smsService.setParams("136698556245");
return smsService;
}
}
public static class EmailFactory extends AbstractMessageFactory {
private static final EmailFactory INSTANCE = new EmailFactory();
private EmailFactory(){
}
public static EmailFactory getInstance(){
return INSTANCE;
}
@Override
public MessageService create() {
EmailServiceImpl emailService = new EmailServiceImpl();
emailService.setParams("216498@qq.com");
return emailService;
}
}
使用示例
MessageService sms = AbstractMessageFactory.createMessage(0);
sms.sendMessage();
MessageService email = AbstractMessageFactory.createMessage(1);
email.sendMessage();
创建对象时添加公共配置
上面的方式需要我们传入参数给抽象工厂类中方法,让其来给我们选择具体的实现方式;但是调用者其实是知道需要那个实现的,因此如果创建的方式不会经常的发生改变,我们可以采用如下方式,由调用者自己去调用即可。
消息发送的业务接口
public interface Message {
/**
* 发送消息
*/
void sendMessage();
}
public static class SmsMessage implements Message {
@Override
public void sendMessage() {
System.out.println("短信发送逻辑");
}
}
public static class EmailMessage implements Message {
@Override
public void sendMessage() {
System.out.println("邮件发送逻辑");
}
}
抽象工厂的实现
public static abstract class AbstractMessageFactory {
public Message createMessage() {
commonCreate();
return specialCreate();
}
private void commonCreate() {
System.out.println("公共配置信息");
}
/**
* 特殊的构建
* @return 返回生成的示例
*/
protected abstract Message specialCreate();
}
public static class SmsMessageFactory extends AbstractMessageFactory {
private static final SmsMessageFactory INSTANCE = new SmsMessageFactory();
private SmsMessageFactory() {}
public static SmsMessageFactory getInstance() {
return INSTANCE;
}
@Override
public Message specialCreate() {
System.out.println("生成短信消息逻辑");
return new SmsMessage();
}
}
public static class EmailMessageFactory extends AbstractMessageFactory {
private static final EmailMessageFactory INSTANCE = new EmailMessageFactory();
private EmailMessageFactory() {}
public static EmailMessageFactory getInstance() {
return INSTANCE;
}
@Override
public Message specialCreate() {
System.out.println("生成邮件消息逻辑");
return new EmailMessage();
}
}
使用示例
Message emailMessage = EmailMessageFactory.getInstance().createMessage();
emailMessage.sendMessage();
Message smsMessage = SmsMessageFactory.getInstance().createMessage();
smsMessage.sendMessage();
抽象工厂模式
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
适用场景:当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。
说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立工厂来对产品进行创建,则更合适一点。
抽象工厂模式与工厂方法模式的区别:
- 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
- 在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。
再通俗来讲就是:抽象工厂模式是针对不同类的组合,而工厂方法模式是针对一个类。
下面我们通过保险套餐来举例,下面先定义保险的业务接口和实现
public interface PensionInsurance {
void execute();
}
public class PensionInsuranceA implements AbstractFactoryPattern.PensionInsurance {
@Override
public void execute() {
System.out.println("养老保险套餐A");
}
}
public class PensionInsuranceB implements AbstractFactoryPattern.PensionInsurance {
@Override
public void execute() {
System.out.println("养老保险套餐B");
}
}
public interface AccidentInsurance {
void execute();
}
public class AccidentInsuranceA implements AbstractFactoryPattern.AccidentInsurance {
@Override
public void execute() {
System.out.println("意外保险套餐A");
}
}
public class AccidentInsuranceB implements AbstractFactoryPattern.AccidentInsurance {
@Override
public void execute() {
System.out.println("意外保险套餐B");
}
}
原始的方式,通过手动创建
使用示例,下面的示例中我们根据业务需要进行组合不同的保险套餐。
// 养老保险套餐A+意外保险套餐B
PensionInsuranceA pensionInsurance1 = new PensionInsuranceA();
AccidentInsuranceB accidentInsurance1 = new AccidentInsuranceB();
pensionInsurance1.execute();
accidentInsurance1.execute();
System.out.println("===============");
// 养老保险套餐B+意外保险套餐B
PensionInsuranceB pensionInsurance2 = new PensionInsuranceB();
AccidentInsuranceB accidentInsurance2 = new AccidentInsuranceB();
pensionInsurance2.execute();
accidentInsurance2.execute();
System.out.println("===============");
// 养老保险套餐B+意外保险套餐A
PensionInsuranceB pensionInsurance3 = new PensionInsuranceB();
AccidentInsuranceA accidentInsurance3 = new AccidentInsuranceA();
pensionInsurance3.execute();
accidentInsurance3.execute();
使用抽象工厂模式实现
定义工厂来进行组合创建
public interface InsuranceFactory {
/**
* 养老保险套餐
*/
PensionInsurance createPensionInsurance();
/**
* 意外保险套餐
*/
AccidentInsurance createAccidentInsurance();
}
public static class InsuranceFactory1 implements InsuranceFactory {
private static final InsuranceFactory1 INSTANCE = new InsuranceFactory1();
private InsuranceFactory1() {}
public static InsuranceFactory1 getInstance() {
return INSTANCE;
}
@Override
public PensionInsurance createPensionInsurance() {
return new PensionInsuranceA();
}
@Override
public AccidentInsurance createAccidentInsurance() {
return new AccidentInsuranceB();
}
}
public static class InsuranceFactory2 implements InsuranceFactory {
private static final InsuranceFactory2 INSTANCE = new InsuranceFactory2();
private InsuranceFactory2() {}
public static InsuranceFactory2 getInstance() {
return INSTANCE;
}
@Override
public PensionInsurance createPensionInsurance() {
return new PensionInsuranceB();
}
@Override
public AccidentInsurance createAccidentInsurance() {
return new AccidentInsuranceB();
}
}
public static class InsuranceFactory3 implements InsuranceFactory {
private static final InsuranceFactory3 INSTANCE = new InsuranceFactory3();
private InsuranceFactory3() {}
public static InsuranceFactory3 getInstance() {
return INSTANCE;
}
@Override
public PensionInsurance createPensionInsurance() {
return new PensionInsuranceB();
}
@Override
public AccidentInsurance createAccidentInsurance() {
return new AccidentInsuranceA();
}
}
使用示例
// 养老保险套餐A+意外保险套餐B
PensionInsurance pensionInsurance1 = InsuranceFactory1.getInstance().createPensionInsurance();
AccidentInsurance accidentInsurance1 = InsuranceFactory1.getInstance().createAccidentInsurance();
pensionInsurance1.execute();
accidentInsurance1.execute();
System.out.println("===============");
// 养老保险套餐B+意外保险套餐B
PensionInsurance pensionInsurance2 = InsuranceFactory2.getInstance().createPensionInsurance();
AccidentInsurance accidentInsurance2 = InsuranceFactory2.getInstance().createAccidentInsurance();
pensionInsurance2.execute();
accidentInsurance2.execute();
System.out.println("===============");
// 养老保险套餐B+意外保险套餐A
PensionInsurance pensionInsurance3 = InsuranceFactory3.getInstance().createPensionInsurance();
AccidentInsurance accidentInsurance3 = InsuranceFactory3.getInstance().createAccidentInsurance();
pensionInsurance3.execute();
accidentInsurance3.execute();
使用抽象工厂模式后,让某个组合需要修改时,只需要修改工厂类即可;其他调用方几乎不做任何修改。但是这样也有缺点,如果新增加了一个产品,几乎所有的工厂类都需要修改,如果产品的创建比较复杂那么扩展的工作会比较大。虽然也可以将组合封装在一个方法中,但是如果业务复杂那么代码会比较臃肿,因此我们将其封装到各个工厂类中去,这样代码层次会更加鲜明。