工厂方法模式才是真正的工厂模式,前面讲到的静态工厂模式实际上不能说是一种真正意义上的设计模式,只是一种变成习惯。
工厂方法的类图:
这里面涉及到四个种类:
1、抽象产品: Product
2、具体产品:ConcreteProduct
3、抽象工厂:Factory
4、具体工厂:ConcreateFactory
下面实际例子说明
/**
* 抽象工厂类:CarFactory
*/
public abstract class CarFactory {
public abstract <T extends Car>T createCar(Class<T> clazz);
}
/**
* 具体工厂类:ChinaCarFactory
*/
public class ChinaCarFactory extends CarFactory {
@Override
public <T extends Car> T createCar(Class<T> clazz) {
String className = clazz.getName();
Car car = null;
try {
car = (Car) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) car;
}
}
/**
* 抽象产品类:Car
*/
public abstract class Car {
/**
* 产品抽象方法,将会由具体产品类实现
*/
public abstract void driving();
}
/**
* 具体产品类:BenZCar
*/
public class BenZCar extends Car {
@Override
public void driving() {
System.out.println("BenZCar is Driving!!!");
}
}
/**
* 具体产品类:BMWCar
*/
public class BMWCar extends Car {
@Override
public void driving() {
System.out.println("BMWCar is Driving!!!");
}
}
测试:
CarFactory carFactory = new ChinaCarFactory();
BMWCar bmw = carFactory.createCar(BMWCar.class);
bmw.driving();
CarFactory carFactory = new ChinaCarFactory();
BenZCar benZCar = carFactory.createCar(BenZCar.class);
benZCar.driving();
打印结果
I/System.out: BMWCar is Driving!!!
I/System.out: BenZCar is Driving!!!
上面是一个简单的例子,但是能够看出来,工厂方法使得一个类的初始化延迟到了子类,至于生产出什么产品工厂自己是不知道的,完全由外部控制,这里就是个“依赖倒置”,前面的简单工厂模式,高层的工厂类依赖于下层的各个具体产品类,当要增加类型的时候上层会跟着变动,依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。
上面的工厂方法模式中,具体的工厂类完全不会依赖于具体产品类了,而是依赖于与其父类--抽象工厂同在一个层次的抽象产品类,至于具体会生产出什么具体产品完全由外部控制,具体的工厂类处于下层,抽象的产品类处于上层,刚好倒置过来。
上面代码对应的UML类图如下:
借用一下百度来的概念:
依赖倒置原则
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。