工厂模式(Factory Pattern)属于创建型模式,分为简单工厂模式、工厂方法模式和抽象工厂模式;有的地方是把工厂模式和抽象工厂模式区分开来,工厂模式只包括简单工厂模式、工厂方法模式;其实怎么划分因人而异,最主要的是要能够知道这几种模式的思想,并且了解他们的异同点,知道在哪种场景下适合用哪种模式即可!
我们之前创建一个对象,都是通过new来直接创建,例如下面的代码,这样做的缺点就是客户端要了解手机接口下的所有实现类,只有了解了接口和实现类才能去创建具体的手机对象,并且,要是创建手机对象需要传递很多参数的话,那么会给客户端带来很多麻烦。
//手机接口
public interface Phone {
void name();
}
//小米手机
public class XiaomiPhone implements Phone{
@Override
public void name() {
System.out.println("小米手机");
}
}
//华为手机
public class HuaweiPhone implements Phone{
@Override
public void name() {
System.out.println("华为手机");
}
}
//客户端
public class Client {
public static void main(String[] args) {
//创建小米手机类
Phone phone=new XiaomiPhone();
phone.name();
//创建华为手机类
Phone phone2=new HuaweiPhone();
phone2.name();
}
}
1. 简单工厂模式
类图:
代码示例:
手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了工厂类,并且对客户端代码进行修改
//生产手机的工厂
public class factory {
//生产手机
public static Phone make(String msg){
if("小米手机".equals(msg)){
return new XiaomiPhone();
}else if("华为手机".equals(msg)){
return new HuaweiPhone();
}else{
return null;
}
}
}
//客户端
public class Client {
public static void main(String[] args) {
//通过工厂创建对象
Phone phone = factory.make("小米手机");
phone.name();
}
}
对简单工厂模式的分析: 简单工厂模式把创建对象的能力交给工厂,客户端要想创建一个对象无需知道对象创建的内部细节,只需要声明对象的类型,通过工厂来获取我们想要的对象。工厂模式的缺点是违反ocp原则,例如我们要增加一个产品,那么需要修改原有的代码,也就是需要修改工厂类的判断逻辑,增加一层判断。
2. 工厂方法模式
类图:
代码示例:
手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了抽象工厂、生产小米手机的工厂、生产华为手机的工厂,并且对客户端代码进行修改
//生产手机的工厂接口
public interface factory {
//提供生产手机的方法
Phone make();
}
//生产小米手机的具体工厂
public class XiaomiFactory implements factory{
@Override
public Phone make() {
return new XiaomiPhone();
}
}
//生产华为手机的具体工厂
public class HuaweiFactory implements factory{
@Override
public Phone make() {
return new HuaweiPhone();
}
}
//客户端
public class Client {
public static void main(String[] args) {
//通过小米工厂创建小米手机对象
Phone phone = new XiaomiFactory().make();
phone.name();
}
}
对工厂方法模式的分析: 工厂方法模式解决了简单工厂模式出现的弊端,也就是满足了ocp原则,例如我们要增加一个产品,步骤就是编写一个产品类去实现产品接口,另外还需要编写一个该产品的工厂去实现抽象工厂,而不需要修改原有的代码,缺点就是每扩展一个产品就需要创建该产品类以及生产该产品的工厂类,会大大增加类的数量,结构复杂。
简单工厂模式和工厂方法模式的对比
如果从结构复杂度、代码复杂度、编程复杂度和管理上的复杂度来考虑,我们会使用简单工厂模式,而如果从设计原则来说,譬如我们不能违反ocp原则,那么就得选择工厂方法模式;虽然工厂方法模式更符合设计模式的思想和原则,但由于简单工厂模式比较简单,所以在实际业务中,会更多的使用简单工厂模式。
3. 抽象工厂模式
类图:
代码示例:
手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了路由器接口、小米路由器、华为路由器、抽象工厂、生产小米系列产品的工厂、生产华为系列产品的工厂,并且对客户端代码进行修改
//路由器接口
public interface Router {
void name();
}
//小米路由器
public class XiaomiRouter implements Router{
@Override
public void name() {
System.out.println("小米路由器");
}
}
//华为路由器
public class HuaweiRouter implements Router{
@Override
public void name() {
System.out.println("华为路由器");
}
}
//抽象工厂
public interface factory {
//生产手机
Phone makePhone();
//生产路由器
Router makeRouter();
}
//小米工厂:生产小米手机、小米路由器
public class XiaomiFactory implements factory{
@Override
public Phone makePhone() {
return new XiaomiPhone();
}
@Override
public Router makeRouter() {
return new XiaomiRouter();
}
}
//华为工厂:生产华为手机、华为路由器
public class HuaweiFactory implements factory{
@Override
public Phone makePhone() {
return new HuaweiPhone();
}
@Override
public Router makeRouter() {
return new HuaweiRouter();
}
}
//客户端
public class Client {
public static void main(String[] args) {
System.out.println("==========小米系列产品========");
//创建小米工厂
factory f=new XiaomiFactory();
//通过小米工厂创建小米手机
Phone phone = f.makePhone();
phone.name();
//通过小米工厂创建小米路由器
Router router = f.makeRouter();
router.name();
}
}
对抽象工厂模式的分析: 抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类,优点是将一个系列的产品统一到一起创建;缺点是规定了所有可能被创建的产品集合,产品族中扩展新的产品困难。
工厂方法模式与抽象工厂模式的区别:
关于二者的区别,我个人看过较好的解释是从产品族和产品等级来进行阐述,下面附上一张从网上拷贝过来的关于产品族和产品等级的图片
工厂方法模式只能生产一种类型的产品,但是支持同等级产品的扩展,例如上面的手机工厂,只能生产手机,而如果要生产其他产品,例如路由器,那么需要修改工厂类,违反ocp,如果进行的是同等级产品的扩展,例如要生产小米手机、华为手机等,不需要修改工厂类,只需要增加生产该等级产品的工厂子类即可,符合ocp。
而抽象工厂模式支持的是同一系列产品的创建,也就是同一产品族,例如小米系列产品,华为系列产品,抽象工厂模式解决了工厂方法模式只能创建一种类型产品的弊端,并且支持的是同一产品族的扩展。
应用场景:
- JDK中Calendar的getInstance方法就用到了简单工厂模式
- Spring中的IOC容器也用到了工厂模式,把创建对象的能力都交给IOC容器,换句话说,我们要创建某个对象实例,只需要从spring工厂中拿即可。
在Spring中有两个最基本的工厂,BeanFactory和ApplicationContext。BeanFactory是Spring框架的基础设施,面向的是Spring本身,也就是用于创建Spring扩展的其他内容,如Spring Security、Spring JDBC等,而ApplicationContext这个工厂是面向开发者的,也就是应用上下文——配置文件等,开发者能够使用这个工厂实现自己的功能。