简单工厂模式的思想很简单:根据传入的参数,工厂的produce()方法创建不同类的对象。
首先,由于创建出来的对象分数不同的Class,所以这些Class都应该inherit一个parent class,考虑到我们对接口编程的思想,我们定义一个继承关系:
Car
public interface Car {
public void go();
}
Bus
public class Bus implements Car {
@Override
public void go() {
System.out.println("Bus is going...");
}
}
Truck
public class Truck implements Car {
@Override
public void go() {
System.out.println("Truck is going...");
}
}
接下来需要定义工厂和参数类:
CarType
public enum CarType {
Bus, Truck
}
CarFactory,考虑到调用者使用的方便,我们使用静态方法创建Car的实例。实际使用中更有可能的是参数并不是CarType,而是实际的属性值,通过属性值的不同格式或内容创建不同类型的实例(例如,可以使用"Mr. White"的形式创建一个名为"White"的男人,也可以通过"Miss Mary"的形式创建一个"Mary"小姐,这样,传入参数都是String,但创建的对象分别是男人和女人:
public class CarFactory {
public static Car produce(CarType type) {
switch (type) {
case Bus:
return new Bus();
case Truck:
return new Truck();
default:
return null;
}
}
}
最后通过例子来测试一下:
public class Test {
public static void main(String[] args) {
Car car = CarFactory.produce(CarType.Bus);
car.go();
}
}
通过上面的例子我们能够知道:
- 如果需要扩展Car的继承类,只需要编写新的类,并且在CarFactory的produce()方法中增加逻辑即可;
- 因为增加Car的具体实现类需要修改produce方法,所以灵活性不是很强;
- 关键业务代码都在Factory中,没能很好的实现“松耦合”;
针对以上现实,实际开发中我们存在另外一种情况,我们通过传入的参数(类名)确定生产出的对象:
改进后的Factory类:
public class CarFactory {
public static Car produce(CarType type) {
switch (type) {
case Bus:
return new Bus();
case Truck:
return new Truck();
default:
return null;
}
}
public static Car produce(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> carClass = Class.forName(type);
return (Car) carClass.newInstance();
}
}
测试类代码:
public class Test {
public static void main(String[] args) {
// Car car = CarFactory.produce(CarType.Bus);
// car.go();
Car car;
try {
car = CarFactory.produce("com.freesoft.designpattern.simplefactory.Bus");
car.go();
car = CarFactory.produce("com.freesoft.designpattern.simplefactory.Truck");
car.go();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
这样如果今后需要创建一个新的汽车类型(Sedan),我们仅需要编写Sedan这个Class即可,在测试类中就可以通过传入类名创建Sedan对象,而无需修改Factory代码。