定义:定义一个创建对象的接口,但让实现这个接口的子类来决定实例化哪个类,工厂方法让类的实例化推迟到子类进行。
工厂方法模式是一种创建型设计模式,工厂方法模式相比于抽象工厂它更侧重于产品等级,实现同一个抽象工厂接口的所有子类创建的对象通常都是同一个产品等级的。为了更好的学习工厂方法模式先来了解下产品等级和产品族,相同的产品等级就是相同的产品,像美的冰箱、格力冰箱、海尔冰箱,它们都是冰箱,它们的产品等级都相同,虽然厂家不同。美的冰箱、美的空调和美电风扇,他们虽然不是同一个产品等级的,但是他们都来自同一家厂商美的,因此他们的产品族相同。
工厂方法模式的角色:
Product:抽象产品。
ConcreteProduct:具体产品类,实现Product接口。
Factory:抽象工厂类,该方法返回一个Product类型的对象。
ConcreteFactory:具体工厂类,返回ConcreteProduct类型的对象。
开始编写代码,以上面的冰箱为例。
抽象产品:
//抽象的冰箱类
public abstract class Fridge {
public abstract void info();
}
抽象工厂:
//抽象的工厂类
public abstract class Factory {
public abstract Fridge createFridge();
}
现在我们要创建美的冰箱,就创建一个继承抽象产品的美的冰箱类,创建一个继承抽象工厂的美的冰箱工厂类。
美的冰箱:
public class MediaFridge extends Fridge{
private String type="美的冰箱";
@Override
public void info() {
System.out.println("冰箱类别:"+type);
}
}
美的冰箱工厂:
//具体的美的工厂
public class MediaFactory extends Factory{
@Override
public Fridge createFridge() {
return new MediaFridge();
}
}
客户端
public class Test {
public static void main(String[] args) {
Factory mediaFactory=new MediaFactory();
Fridge mediaFridge=mediaFactory.createFridge();
mediaFridge.info();
}
}
如果现在又需要生产海尔冰箱,只需要创建继承抽象产品的海尔冰箱类和继承抽象工厂的海尔工厂类。
海尔冰箱:
public class HaierFridge extends Fridge{
private String type="海尔冰箱";
@Override
public void info() {
System.out.println("冰箱类别:"+type);
}
}
生产海尔冰箱的工厂:
public class HaierFridge extends Fridge{
private String type="海尔冰箱";
@Override
public void info() {
System.out.println("冰箱类别:"+type);
}
}
以后生产格力冰箱也是如此,可以看到工厂方法模式很好的遵循开闭原则,不管我们以后生产什么冰箱都可以通过扩展来实现,只要扩展对应的具体工厂和具体冰箱而不需要修改已有的类。
不过这样写也有不好的地方,增加了类的数量。因此如果情况允许,我们也可以这样简写:
抽象工厂:
public abstract class FridgeFactory {
public abstract <T extends Fridge> T createFridge(Class<T> clz);
}
具体工厂:
public class FridgeFactoryImpl extends FridgeFactory{
@Override
public <T extends Fridge> T createFridge(Class<T> clz) {
String className=clz.getName();
Fridge fridge = null;
try {
fridge = (Fridge)Class.forName(className).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return (T) fridge;
}
}
可以通过反射来创建冰箱对象,这样不管创建什么冰箱,只要把它的Class对象传进来就好了,此时只需要一个工厂类。
客户端:
FridgeFactory factory=new FridgeFactoryImpl();
Fridge fridge=factory.createFridge(MediaFridge.class);
fridge.info();