精通设计模式之工厂方法模式
工厂方法模式
工厂方法模式又被称为虚拟构造器(Virtual Constructor)
作用
定义用于创建对象的接口,但是让子类决定要实例化哪个类。工厂方法将类实例化推迟到子类。
说明
真实案例
- 铁匠制造武器。精灵需要精灵武器和兽人需要兽医武器。根据手头的客户,正确的类型的铁匠被召唤。
- 发送器发送信息。短信发送器发送短信息和邮件发送器发送邮件信息。根据业务需求,调用正确类型的发送器发送信息。
简而言之
工厂方法模式提供了一种将实例化逻辑委托给子类的方法
维基百科定义
在基于类的编程中,工厂方法模式是使用工厂方法来处理创建对象的问题的创建模式,而不必指定将要创建的对象的确切类。这可以通过调用工厂方法(在接口中指定并由子类实现)来实现,或者在基类中实现,并且可选地被派生类覆盖,而不是调用构造函数。
程序示例
以我们的信息发送器为例。首先我们有一个信息发送器接口和一些实现
/**
* Description: 定义发送者接口
* <br /> Author: vimx86
*/
public interface Sender {
/**
* 发送信息
*/
void send();
}
/**
* Description: 邮件发送者
* <br /> Author: vimx86
*/
public class MailSender implements Sender {
@Override
public void send() {
System.out.println("邮件发送者发送了一封邮件!");
}
}
/**
* Description: 短信息发送者
* <br /> Author: vimx86
*/
public class SmsSender implements Sender {
@Override
public void send() {
System.out.println("短信息发送者发送了一封邮件!");
}
}
定义信息发送器生产工厂
/**
* Description: 发送工厂(普通工厂模式)
* <br /> Author: vimx86
*/
public class SimpleSendFactory {
/**
* 根据发送者类型名称生产对应发送者
*
* @param type 发送者类型
* @return 具体发送者
*/
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
现在,根据发送器类型调用正确的信息发送器并发送信息。
/**
* Description: 测试普通工厂模式
* <br /> Author: vimx86
*/
public class SimpleSendFactoryTest {
@Test
public void test() throws Exception {
SimpleSendFactory factory = new SimpleSendFactory();
Sender sender = factory.produce("sms");
sender.send();
}
}
适用场景
何时使用“工厂方法”模式
- 一个类不能预期它必须创建的对象类
- 一个类希望其子类来指定它创建的对象
- 类将责任委托给几个辅助子类之一,并且您想要本地化哪个助手子类是委托的知识
Known uses
点进去看一看,理解一下 ^_^!!!
* java.util.Calendar
* java.util.ResourceBundle
* java.text.NumberFormat
* java.nio.charset.Charset
* java.net.URLStreamHandlerFactory
* java.util.EnumSet
* javax.xml.bind.JAXBContext
信息发送案例
- 普通工厂模式
- 多个工厂方法模式
- 静态工厂方法模式
工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。
在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,
第三种相对于第二种,不需要实例化工厂类,
所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
工厂方法模式的运用
结合实际业务进行分析运用设计案例
业务场景
获取不同票务商(大众,猫眼,蜘蛛等等)提供的影院实时座位图。
考虑业务扩展,保证有新票务商的接入时不影响当前业务。提供扩展性,可维护性。
分析设计
因为每家票务商都需要提供实时座位图功能,故可抽象出共同的接口 实时座位图提供商
提供实时座位图
功能。
定义实时座位图提供商接口 RealTimeSeats
和实现具体票务商的子类。
public interface RealTimeSeats{
/**
* 获取实时座位图信息
*/
RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest);
}
/**
* Description: 猫眼获取实时座位图
* <br /> Author: vimx86
*/
public class MaoYanRealTimeSeats implements RealTimeSeats{
@Override
public RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest) {
// 猫眼获取实时座位图逻辑调用……
}
}
/**
* Description: 蜘蛛网获取实时座位图
* <br /> Author: vimx86
*/
public class SpiderRealTimeSeats implements RealTimeSeats{
@Override
public RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest) {
// 蜘蛛网获取实时座位图逻辑调用……
}
}
定义获取实时座位图工厂
/**
* Description: 实时座位图工厂
* <br /> Author: vimx86
*/
public class RealTimeSeatsFactory {
public static RealTimeSeats produceSpider() {
return new SpiderRealTimeSeats ();
}
public static RealTimeSeats produceMaoYan() {
return new MaoYanRealTimeSeats ();
}
}
这种工厂方法模式 扩展需要修改工厂类,等我们学习了抽象工厂模式再进一步改进。