平时写项目里的代码,分层一般都是:持久层 》业务层 》表现层,业务层里一般的形式就是:接口api 》 接口api实现类,即
public interface Sender {……}
public class BossSender implements Sender {……}
@Autowired
private Sender sender;
你肯定也这样写过,那么结合标题:简单工厂模式来看看,为什么要这么写?这样写的好处又是什么呢?为什么不直接注入接口的实现类呢?如下示例代码:
public interface Sender {
void send(String content);
}
/**
* 类描述:Sender接口的实现类:BossSender
* 创建人:simonsfan
*/
public class BossSender implements Sender {
@Override
public void send(String content) {
System.out.println(content);
}
}
/**
* 类描述:Sender接口的实现类:WorkerSender
* 创建人:simonsfan
*/
public class WorkerSender implements Sender {
@Override
public void send(String content) {
System.out.println(content);
}
}
/**
* 类描述:模拟客户端调用
* 创建人:simonsfan
*/
public class Client {
public static void main(String[] args) {
Sender sender = new BossSender();
//或者在业务层直接注入
//@Autowired
//private BossSender bossSender;
}
}
结合开头说到分层结构,三个层级之间的交互都是通过接口来实现的,那么接口的核心功能就是"封装隔离",对于外部调用者而言,在上面的代码中就是Client类,在使用Sender接口时候,通过new BossSender()方式来获取了Sender接口的实现类,这样子的话就把接口的实现BossSender暴露给了Client,而实际上调用方是不应该且无需关心接口实现行为的,为了解决这个问题,我们引入了工厂模式。
简单工厂:提供一个工厂类,实现创建实例的功能,而无需关心具体实现。这很符合java面向对象编程的原则之一-依赖倒置原则:要依赖于抽象而不依赖于具体。在代码中的体现就是通过一个工厂类封装创建对象实例的行为,通过某些标识来区分具体创建哪个实例。
/**
* 类描述:简单工厂类,供客户端调用,隐藏创建实现类实例的细节
* 创建人:simonsfan
*/
public class SenderFactory {
public static Sender getInstance(String type) {
//todo something
if ("boss".equals(type)) {
return new BossSender();
} else if ("worker".equals(type)) {
return new WorkerSender();
} else {
return null;
}
}
}
/**
* 类描述:模拟客户端调用
* 创建人:simonsfan
*/
public class Client {
public static void main(String[] args) {
Sender sender = SenderFactory.getInstance("boss");
sender.send("×××");
}
}
这样便把创建Sender接口实现类实例的动作封装起来了,调用端无法了解到具体的实现,但是也把String type这个参数暴露给调用方,也就是说调用端必须很清楚传入的这个type形参到底代表着什么,这样不仅也暴露了部分实现细节,也增加了调用方的使用难度,如果这个类型传的不对,也就无法创建想要的实例,不妥。于是就有了升级版的多个工厂方法:
/**
* 类描述:改造后的简单工厂类,把创建类实例的动作分开
* 创建人:simonsfan
*/
public class SenderFactory {
public Sender createBossSender() {
return new BossSender();
}
public Sender createWorkerSender() {
return new WorkerSender();
}
}
/**
* 类描述:模拟客户端调用
* 创建人:simonsfan
*/
public class Client {
public static void main(String[] args) throws Exception {
SenderFactory factory = new SenderFactory();
//调用createBossSender()就是专门用来生成BossSender实例
factory.createBossSender();
}
}
改造后的简单工厂将创建多个实例的动作分别封装在各自的方法体内,不再通过传递参数来判断生成具体的实例。但是每次调用方要生成实现了同一接口的多个实例,就得先new SenderFactory实例,于是静态工厂又出现了:
/**
* 类描述:改造后的静态工厂类,把创建类实例的动作分开且创建动作是static,可不用new工厂类而直接调用
* 创建人:simonsfan
*/
public class SenderFactory {
public static Sender createBossSender() {
return new BossSender();
}
public static Sender createWorkerSender() {
return new WorkerSender();
}
}
/**
* 类描述:模拟客户端调用静态工厂
* 创建人:simonsfan
*/
public class Client {
public static void main(String[] args) throws Exception {
Sender bossSender = SenderFactory.createBossSender();
bossSender.send("××");
Sender workerSender = SenderFactory.createWorkerSender();
workerSender.send("××");
}
}
静态工厂就是把创建实例的方法给static了,不用new工厂类便可以直接调用。但是从虚拟机的角度来看,结合类加载机制,其实通过调用类的静态方法时也会出发类强制进行"初始化"操作,只是相对于每次都new来说,节省了一些堆内存空间。
结合静态工厂方法来看,其弊端很明显,所有Sender实现类的对象实例创建都依赖于工厂类SenderFactory,如果想扩展程序,例如增加Sender接口的实现类,这个时候使用静态工厂创建实现类的实例就得改工厂类,不符合闭包原则,所以抽象工厂顺势产生,来解决动态创建工厂类的需求。
/**
* 类描述:抽象工厂接口
* 创建人:simonsfan
* 创建时间:2018/12/7
*/
public interface FactoryProducer {
Sender produce();
}
/**
* 类描述:BossFactory的抽象工厂实现类
* 创建人:simonsfan
* 创建时间:2018/12/7
*/
public class BossFactorySenderProducer implements FactoryProducer {
@Override
public Sender produce() {
return new BossSender();
}
}
/**
* 类描述:WorkerFactory抽象工厂实现类
* 创建人:simonsfan
* 创建时间:2018/12/7
*/
public class WorkerFactorySenderProducer implements FactoryProducer {
@Override
public Sender produce() {
return new WorkerSender();
}
}
/**
* 类描述:模拟客户端调用抽象工厂
* 创建人:simonsfan
*/
public class Client {
public static void main(String[] args) throws Exception {
BossFactorySenderProducer bossFactorySenderProducer = new BossFactorySenderProducer();
Sender sender = bossFactorySenderProducer.produce();
sender.send("");
}
}