最近在android下封装一个sdk,用到了工厂模式的一些特性。就打算写篇文件章总结一下。

什么是工厂模式

直接切入主题。 通常工厂模式被分为三类。工厂方法模式,简单工厂模式和抽象方法模式。

工厂方法模式

抽象工厂角色,一个接口或者抽象类。

具体工厂角色,实现或者继承上面的抽象工厂,包含具体的业务处理逻辑。

抽象产品角色,一个接口或者抽象类,描述具体的产品。

具体产品角色,实现抽象产品。

上代码直观些:

//抽象产品角色
public interface Moveable {
void run();
}
//具体产品角色
public class Plane implements Moveable {
@Override
public void run() {
System.out.println("plane....");
}
}
public class Broom implements Moveable {
@Override
public void run() {
System.out.println("broom.....");
}
}
//抽象工厂
public abstract class VehicleFactory {
abstract Moveable create();
}
//具体工厂
public class PlaneFactory extends VehicleFactory{
public Moveable create() {
return new Plane();
}
}
public class BroomFactory extends VehicleFactory{
public Moveable create() {
return new Broom();
}
}
//测试类
public class Test {
public static void main(String[] args) {
VehicleFactory factory = new BroomFactory();
Moveable m = factory.create();
m.run();
}
}

很明显,核心工厂类不负责产品的创建,这样核心类成为一个抽象工厂角色。它的缺点是当产品种类比较多时

,对应的具体工厂类也会非常多,代码结构比较复杂。

简单工厂模式

这种模式其实就是把工厂方法模式中的抽象工厂角色去掉,只有一个具体做事的工厂。看个不同的例子:

//抽象产品角色
public abstract class Car {
public Car(CarType model) {
this.model = model;
doSomething();
}
private void doSomething() {
// Do one time processing here
}
private CarType model = null;
public CarType getModel() {
return model;
}
public void setModel(CarType model) {
this.model = model;
}
}
//具体产品角色
public class LuxuryCar extends Car {
LuxuryCar() {
super(CarType.LUXURY);
construct();
}
@Override
protected void construct() {
System.out.println("Building luxury car");
// add accessories
}
}
//具体产品角色
public class SmallCar extends Car {
SmallCar() {
super(CarType.SMALL);
construct();
}
@Override
protected void construct() {
System.out.println("Building small car");
// add accessories
}
}
//工厂角色
public class CarFactory {
public static Car buildCar(CarType model) {
Car car = null;
switch (model) {
case SMALL:
car = new SmallCar();
break;
case LUXURY:
car = new LuxuryCar();
break;
default:
// throw some exception
break;
}
return car;
}
}
//测试
public class TestFactoryPattern {
public static void main(String[] args) {
System.out.println(CarFactory.buildCar(CarType.SMALL));
System.out.println(CarFactory.buildCar(CarType.SEDAN));
System.out.println(CarFactory.buildCar(CarType.LUXURY));
}
}

由于没有了抽象和具体工厂的概念,一般工厂方法中创建产品的方法都要能过传参指明返回的具体产品对象。它的优点是代码结构简单,缺点也很明显。由于所有的处理都集中在一个工厂中,如果这个工厂出

问题,所有的客户端调用都会有问题。还有就是这种方法违背了OCP(开放封闭原则),也就是每新增一个产品就要修改工厂。当然也违背了单一职责原则。

抽闲工厂模式

这个我没怎么用过,懒得讲了。自己网上搜吧。

为什么要使用工厂模式

核心优点就是隐藏了产品实现类,客户端调用时只要知道接口就行了,比如上面的

public static Car buildCar(CarType model);

返回的是产品类的接口。

那隐藏了具体实现类又有什么好处呢,答案就程序容易扩展。比如上面的Car示例,如果封装API给客户调用,

客户只看到接口Car,实现类他不用关心。如果调用发现这个实现类不好用,还可以换一个实现厂商,或者自己重新实现。

这些修改都不用影响接口的调用。

这种模式的使用示例在一些大型的程序中比比皆是。比java.sql包定义了很多jdbc的接口,大家在进行jdbc编程时都只需要使用Connection、PreparedStatment、ResultSet等接口,而不需要考虑这些接口的具体实现类是什么。每种数据库,如Oracle、SQLServer、DB2的JDBC驱动则是由各个厂商提供具体实现类,来实现统一的JDBC API接口规范。

这里引用一段:

举个jdbc调用的例子: Oracle的jdbc调用:

… …
Class.forName(“oracle.jdbc.driver.OracleDriver”;);
Connection conn=DriverManager.getConnection(jdbcurl,username,password);

SQLServer的jdbc调用:

… …
Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”);
Connection conn=DriverManager.getConnection(jdbcurl,username,password);

MySQL的jdbc调用:

… …
Class.forName(“com.mysql.jdbc.Driver”);
Connection conn=DriverManager.getConnection(jdbcurl,username,password);

这里,DriverManager就是工厂,通过getConnection()方法来生产出数据库连接对象Connection, 用户使用Connect就可以实现JDBC编程了。

但是,DriverManager是怎么知道使用的哪个数据库,使用哪个提供商的JDBC驱动来生产Connectin的吗?答案在这里,原因就在Class.forName()的过程中,Class.forName()是将一个类初始化,这里,调用不同厂商提供jdbc驱动时,使用了不同的jdbc驱动类的类名,该方法会初始化化该Driver类,该类在初始化时(static{}方法中)会初始化一个自己的Driver类实例,并将实例注册到DriverManager中(的一个Vector中),再通过DriverManager中的getConnection()方法找到Driver实例(通过jdbcurl),再调用Driver实例的getConnection()方法。Driver实例也是一个生产Connection接口实例的工厂。DriverManager实际上是一个保存了各个jdbc驱动的一个缓存管理类,缓存了各个驱动程序,并调用各个jdbc的驱动程序生产Connection对象。

可以看出,只需要更改Driver的类名,提供不同的jdbcUrl和用户、密码,就可以生产出一个数据库连接(Connection接口类的实例)。

还有一种情况,一般如果我们自己的封装API给别人调用,为了不让别人看到实现代码会用到混淆。这时我们就可以把实现类混淆只留出接口给外部调用即可。