工厂设计模式
什么是工厂设计模式?
工厂设计模式是将拥有共性的产品抽象封装到工厂类中统一进行管理和创建,以达到降低使用者与产品之间的耦合度的目的一种手段。
工厂设计模式是创建者模式之一,且从结构上被划分为三大类。
三种不同的结构类型,分别对应处理不同的问题。
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
工厂设计模式怎么用?
简单工厂模式
简单工厂模式是最简单,也是最清晰的模式。理解了简单工厂模式,就理解了工厂设计模式的主要思想。
/**
* 工厂设计模式-简单工厂模式
* 发送接口.
*
*/
public interface Sender {
void send();
void sendToAll();
}
/**
* 工厂设计模式-简单工厂模式
* 工厂类
*/
public class SenderFactory {
/**
* 单例
* 私有化构造器
*/
private SenderFactory() {
//Nope
}
/**
* 嵌套类
* 持有外部类对象
*/
private static class SenderFactoryHolder {
private static SenderFactory sf = new SenderFactory();
}
/**
* 获取单例实例
*
* @return
*/
public static SenderFactory getInstanse() {
return SenderFactoryHolder.sf;
}
/**
* 根据参数返回相应发送处理类
*
* @return 邮件/短信发送对象
*/
public Sender createSender(String senderType) {
switch (senderType) {
case "sms":
return new SMSSender();
case "mail":
return new MailSender();
default:
return new SMSSender();
}
}
}
/**
* 工厂设计模式-简单工厂模式
* 短信发送类
*
*/
public class SMSSender implements Sender {
@Override
public void send() {
System.out.print("发送短信");
}
@Override
public void sendToAll() {
System.out.println("群发短信");
}
}
/**
* 工厂设计模式-简单工厂模式
* 客户端
*
*/
public class Client {
public static void main(String[] args) {
SenderFactory factory = SenderFactory.getInstanse();
Sender sd = factory.createSender("sms");
sd.send();
}
}
用户/客户端直接与SenderFactory交互,SenderFactory根据参数决定具体创建的产品,用户最终从SenderFactory中得到了想要的产品。
可见,通过简单工厂模式,达到了解耦用户与产品的效果。但是,这样的结构并不是完美的。
在本例中,SenderFactory掌管了所有的业务逻辑处理。这样的类,我们称为上帝类/全能类。上帝类耦合度非常高,每当需要增加新产品时,就需要更改SenderFactory中的代码。比如我们想要增加FaxSender,则SenderFactory中的逻辑必然就会产生改动,这不符合设计模式的开闭原则(对扩展开放,对修改关闭)。
所以,当需要频繁增加新产品时,我们就需要通过工厂方法模式来解决问题。
工厂方法模式
/**
* 工厂设计模式-工厂方法模式
* 发送接口.
*/
public interface Sender {
void send();
void confrimName();
}
/**
* 工厂设计模式-工厂方法模式
* 短信发送类
*/
public class SMSSender implements Sender {
@Override
public void send() {
System.out.println("发送短信");
}
@Override
public void confrimName() {
System.out.println("确认短信发送对象姓名");
}
}
/**
* 工厂设计模式-工厂方法模式
* 短信发送工厂
*/
public class SMSSenderFactory implements ISenderFactory {
@Override
public Sender createSender() {
return new SMSSender();
}
}
/**
* 工厂设计模式-工厂方法模式
* 邮件发送类
*/
public class MailSender implements Sender {
@Override
public void send() {
System.out.println("发送邮件");
}
@Override
public void confrimName() {
System.out.println("确认邮件发送对象姓名");
}
}
/**
* 工厂设计模式-工厂方法模式
* 邮件发送类制造工厂
*
*/
public class MailSenderFactory implements ISenderFactory {
@Override
public Sender createSender() {
return new MailSender();
}
}
/**
* 工厂设计模式-工厂方法模式
* 传真发送类
*/
public class FaxSender implements Sender {
@Override
public void send() {
System.out.println("发送传真");
}
@Override
public void confrimName() {
System.out.println("确认传真发送对象姓名");
}
}
/**
* 工厂设计模式-工厂方法模式
* 传真发送类制造工厂
*/
public class FaxSenderFactory implements ISenderFactory {
@Override
public Sender createSender() {
return new FaxSender();
}
}
/**
* 工厂设计模式-工厂方法模式
* 测试客户端
*/
public class Client {
public static void main(String[] args) {
// 需要生产短信发送器,给客户发送短信
SMSSenderFactory smsfct = new SMSSenderFactory();
smsfct.createSender().send();
smsfct.createSender().confrimName();
// 需要生产邮件发送器,给客户发送短信
MailSenderFactory mailfct = new MailSenderFactory();
mailfct.createSender().send();
// 需要生产传真发送器,给客户发送短信
FaxSenderFactory faxfct = new FaxSenderFactory();
faxfct.createSender().send();
}
}
有别与简单工厂模式。工厂方法模式中工厂类被抽象成为了接口。而不同的产品对应不同的实现了工厂接口的具体工厂。比如SMSSenderFactory[1]实现了工厂接口,并且只负责生产SMSSender对象产品。当出现新需求,如增加FaxSender产品时,我们不需要改动任何代码,只需要创建相应的FaxSenderFactory与FaxSender就够了。
细心的读者可能已经发现了,工厂方法模式同样拥有一些“致命”缺点,那就是随着产品的增加,相应的工厂类也会同比增加,造成项目文件十分臃肿巨大。于是,为了减少工厂类的出现数量,抽象工厂模式诞生了。
抽象工厂模式
抽象工厂模式若采用“填鸭式”说明,会让人感觉难以理解。
所以让我们先来尝试靠自己的力量解决一下上一小节中的,工厂方法模式所造成的工厂类大量增多的问题,已达到循序渐进地理解抽象工厂模式的目的。
工厂类疯狂增多的根本原因,是单个商品的生产对应了单个工厂。
要减少他们的数量,最容易想到的解决方案则是想办法让一个工厂创建多个产品。然而有了第一小节简单工厂模式的知识,我们还知道要尽可能解耦工厂类,避免创建出全能类/上帝类,给将来的维护扩展造成负担。
例如,在项目进行中,突然需要增加一个Receiver产品,如下:
Receiver类产品:
/**
* 工厂设计模式-抽象工厂模式
* 接收者对象
*/
public interface Receiver {
void receive();
void confirmName();
}
/**
* 工厂设计模式-抽象工厂模式
* 邮件接受对象
*/
public class MailReceiver implements Receiver {
@Override
public void receive() {
System.out.println("接受邮件");
}
@Override
public void confirmName() {
System.out.println("确认邮件接受者姓名");
}
}
/**
* 工厂设计模式-抽象工厂设计模式
* 传真接收器
*
*/
public class FaxReceiver implements Receiver {
@Override
public void receive() {
System.out.println("接受传真");
}
@Override
public void confirmName() {
System.out.println("确认传真发送方姓名");
}
}
/**
* 工厂设计模式-抽象工厂设计模式
* 短信接受对象
*
*/
public class SMSReceiver implements Receiver {
@Override
public void receive() {
System.out.println("接受短信");
}
@Override
public void confirmName() {
System.out.println("确认短信接受者姓名");
}
}
如果按照工厂方法设计模式的思路,上面这3个Receiver需要在项目中增加3个对应的具体工厂类。这显然是不太理想的做法。
那么,有没有更加理想的做法呢?
继续分析,本例中mailSender/mailReceiver,faxSender/faxReceiver,SMSSender/SMSReceiver刚好能够组合为三对产品组合。如果一个工厂能够生产一对组合产品,是不是只需要三个工厂就能解决我们的需求呢?
在理清了思路后,我们开始动手写代码做一些尝试。
为了方便,我们将mailSender/mailReceiver这样一对产品,称为一个产品簇。而mailSender,faxSender,SMSSender3个产品,称为3个产品等级。
Sender类产品:
/**
* 工厂设计模式-抽象工厂模式
* 信息发送产品统一接口
*/
public interface Sender {
void send();
void confrimName();
}
/**
* 工厂设计模式-抽象工厂模式
* 短信发送对象
*/
public class SMSSender implements Sender {
@Override
public void send() {
System.out.println("发送短信");
}
@Override
public void confrimName() {
System.out.println("确认短信发送对象姓名");
}
}
/**
* 工厂设计模式-抽象工厂模式
* 邮件发送类
*
*/
public class MailSender implements Sender {
@Override
public void send() {
System.out.println("发送邮件");
}
@Override
public void confrimName() {
System.out.println("确认邮件发送对象姓名");
}
}
/**
* 工厂设计模式-抽象工厂设计模式
* 传真发送器
*
*/
public class FaxSender implements Sender {
@Override
public void send() {
System.out.println("发送传真");
}
@Override
public void confrimName() {
System.out.println("确认传真发送姓名");
}
}
产品簇factory类:
一个产品簇工厂中,能够生产一个系列的产品。而非单个产品。
/**
* 工厂设计模式-抽象工厂模式
* 抽象工厂类
*
*/
public interface AbstractMsgHandlerFactory {
// 创建发送器方法
Sender createSender();
// 创建接收器方法
Receiver createReceiver();
}
/**
* 工厂设计模式-抽象工厂设计模式
* 传真工厂
*/
public class FaxHandlerFactory implements AbstractMsgHandlerFactory {
@Override
public Sender createSender() {
return new FaxSender();
}
@Override
public Receiver createReceiver() {
return new FaxReceiver();
}
}
/**
* 工厂设计模式-抽象工厂方法设计模式
* 邮件工厂
*
*/
public class MailHandlerFactory implements AbstractMsgHandlerFactory {
@Override
public Sender createSender() {
return new MailSender();
}
@Override
public Receiver createReceiver() {
return new MailReceiver();
}
}
/**
* 工厂设计模式-抽象工厂方法设计模式
* 短信工厂
*/
public class SMSHandlerFactory implements AbstractMsgHandlerFactory {
@Override
public Sender createSender() {
return new SMSSender();
}
@Override
public Receiver createReceiver() {
return new SMSReceiver();
}
}
客户端
/**
* 工厂设计模式-抽象工厂方法模式
* 客户端
*
*/
public class Client {
public static void main(String[] args) {
// 需要处理邮件.
AbstractMsgHandlerFactory mailFactory = new MailHandlerFactory();
mailFactory.createSender().send();
mailFactory.createReceiver().receive();
// 需要处理短信
AbstractMsgHandlerFactory smsFactory = new SMSHandlerFactory();
smsFactory.createSender().send();
smsFactory.createReceiver().receive();
// 需要处理传真
AbstractMsgHandlerFactory faxFactory = new FaxHandlerFactory();
faxFactory.createSender().send();
faxFactory.createReceiver().receive();
}
}
通过抽象工厂设计模式,将代码的共性重新进行了抽象,从而使代码结构发生了变化。现在一个工厂不再生产单个产品,而是生产一个产品簇。比如SMSHandlerFactory工厂生产与SMS有关的产品簇的全系列产品。他们包括SMSReceiver与SMSSender。
将来若需要进行产品等级的扩展,如加入了Forwarder类产品,我们不需要增加新的工厂类,仅需要在工厂接口中增加Forwarder的生产接口,再更改相应实现代码就可以了。
若将来需要进行产品簇的扩展,如增加了PhoneSender,PhoneRecevier系列产品,则仅需要增加一个phoneFactory就可以解决问题。而不需要更改原有代码。
也就是说,该设计模式再具备了一定的扩展性的同时,又尽可能的控制了类的大量扩张。
总结
- 工厂设计模式分为三类。简单工厂,工厂方法,抽象工厂。
- 三种模式没有高下之分。
- 简单工厂模式适合用于项目需求简单,产品很少并且几乎没有扩展可能性的情况。
- 工厂方法模式适合用于产品簇单一,但却经常发生改变的情况。
- 抽象工厂适合用于项目拥有多个产品簇,且产品等级经常发生改变,并且还需要尽可能控制项目体积的情况。
- 笔者倾向于简单工厂方法>抽象工厂模式>工厂方法模式的思考方式。原因在于简单的问题用简单工厂方法已经足够,而稍微复杂的问题则几乎会面临扩展和工厂类大量增多的情况,用抽象工厂模式更能有效的解决问题。
-
使用InnerClassHolder来实现了单例。点击参考相关文章。 ↩