介绍
简单工厂模式事实上并不属于23种设计模式中的任何一个模式,但是它的工厂思想是有关工厂的基本思想,这个思想也是非常常用的,了解了它之后我们会对工厂模式有更深的理解
具体实现
工厂角色
ProductApi:生产者API,用于定义生产者的行为规范,即抽象接口
ConcreteProduct:具体的生产者角色,具体已经实现接口的生产者
Factory:工厂,根据参数创建具体的生产者角色
Client:消费者,需要使用具体的某个生产者
代码实现
以程序员的一天为例代码实现
ProductApi类(程序员接口)
public interface Programmer {
void dayLife();
}
ProductRole(程序员1和程序员2)
public class Programmer1 implements Programmer{
@Override
public void dayLife() {
System.out.println("程序员1:起床-敲代码-吃饭-睡觉");
}
}
public class Programmer2 implements Programmer{
@Override
public void dayLife() {
System.out.println("程序员2:起床-敲代码-吃饭-陪女朋友逛街-睡觉");
}
}
Factory(程序员工厂)
public class ProgrammerFactory {
public Programmer getProgrammer(String type) {
if ("程序员1".equals(type)) {
return new Programmer1();
} else if ("程序员2".equals(type)) {
return new Programmer2();
}
return null;
}
}
Client(用于测试的消费者1)
public class Client1 {
public static void main(String[] args) {
ProgrammerFactory programmerFactory = new ProgrammerFactory();
Programmer programmer = programmerFactory.getProgrammer("程序员1");
programmer.dayLife();
}
}
由代码可以看出工厂类其实就是个生产间,专门负责生产程序员,Client消费端不需要关心自己生产出程序员的细节,消费方只需要传一个参数进去便可取出需要的程序员,那么如果没有工厂类会发生什么呢?
如果把工厂类去掉,那么Client1的代码就会变成这样
public class Client1 {
public static void main(String[] args) {
// type一般不是固定的
String type = "程序员1";
Programmer programmer = null;
if ("程序员1".equals(type)) {
programmer = new Programmer1();
} else if ("程序员2".equals(type)) {
programmer = new Programmer2();
}
programmer.dayLife();
}
}
这样如果只有一个Client还好,但是一旦有了Client2、Client3等等,那么每个Client都要写这段代码,首先第一个问题就是代码冗余,再一个一旦这段代码需要更改,那么所有Client都要更改,代价太大了;factory的作用其实就是将所有Client的重复代码合并成一个方法,所有Client都能使用,方法需要更改时只用改factory就完事了,代码既简洁又一定程度上增强了扩展性
代码优化
事实上上述代码还可优化,每次增加一个新的程序员时,factory就需要再加一个else判断,这违反了开闭原则,可使用反射来优化代码
public class ProgrammerFactory {
public Programmer getProgrammer(Class classs) {
Programmer programmer = null;
try {
programmer = (Programmer) Class.forName(classs.getName()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return programmer;
}
}
public class Client1 {
public static void main(String[] args) {
// 假设此处的arg是外界传入的,且不知道具体是接口的哪个实现类
Programmer arg = new Programmer1();
ProgrammerFactory programmerFactory = new ProgrammerFactory();
Programmer programmer = programmerFactory.getProgrammer(arg.getClass());
programmer.dayLife();
}
}
这样不论如何扩展程序员的实现类,factory都能找到对应的实现类也不需要改变代码
【一般参数是个抽象接口,而不是具体的实现类,这是面向接口编程的思想】
优缺点
优点
封装思想:帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程
解耦:通过简单工厂,实现了客户端和具体实现类的解耦。客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象,一定程度上便于后续扩展
缺点
由于简单工厂是静态工厂,无法形成以继承为体系的工厂结构(此处可看下一篇博客工厂模式)工厂模式
在工厂中违反开闭原则,如果不断地添加新生产者,工厂的生产职责可能越来越复杂,可能有人问这里不是用反射可以优化吗,但不是每个需求都能用反射优化(需求很多总会有不满足的),工厂既承担了程序员1的加工又承担了程序员2的加工,承担了所有程序员的加工过程
使用时机
- 如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选用简单工厂,让客户端通过工厂来获取相应的接口,而无须关心具体的实现
- 如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制
总的来说简单工厂重视封装思想和集中控制管理对象的生命周期