Factory Method(工厂方法)
工厂,顾名思义是用来生产东西的,那么在平常Coding的过程中,能用在什么地方呢?
在任何需要生成复杂对象的地方都可以使用工厂模式,当然,如果只是用new就可以创建的对象就没必要使用工厂模式了
Factory Method(工厂方法)的UML类图
如上图
- Product:产品类接口,用于规范产品类
- ConcreteProduct:具体的产品类
- Creator:抽象的工厂方法
- ConcreteCreator:工厂方法的具体实现类,用于生产具体的产品
Talk is cheap, show you my code.
首先先定义产品类接口
public interface Product {
void method();
}
然后,接着定义具体产品类
Concrete Product
public class ConcreteProduct implements Product {
@Override
public void method() {
System.out.println("This is product");
}
}
那么对于具体产品就要有对应的工厂,在此之前先定义一个抽象的工厂类
public abstract class Factory {
public abstract Product createProduct();
}
具体工厂
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProduct(); // create the product
}
}
OK,我们来测试一下
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.method();
Result:
This is product
但是,难道我们们每一个产品都要创建一个对应的产品工厂吗?一两个产品还好,但是如果是10个呢?50个呢?这样一来,都会多出很多的类,使得工程更加的冗余
所以在这里,我们完全可以利用反射来减少代码量
为了达成目的,我们首先就需要对抽象工厂做出修改,具体实现如下
public abstract class Factory {
public abstract <T extends Product> T createProduct(Class<T> clz);
}
从上面的代码中可以看出,我们需要让传入一个类,然后经过操作返回一个具体的产品。所以核心就是如何实现这个具体工厂,接着往下看。现在修改具体工厂实现
public class ConcreteFactory extends Factory{
@Override
public <T extends Product> T createProduct(Class<T> clz) {
Product product = null;
try {
product = (Product) Class.forName(clz.getName()).newInstance();
} catch(Exception e) {
e.printStackTrace();
}
return (T) product;
}
}
这里我们通过利用了反射机制,通过传入具体产品类名来获得对应产品类实例,从而我们只需要这一个具体工厂实例,大大减少了代码量
现在我们再来测试一下
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProduct.class);
product.method();
测试结果同上面一样
经过上面的编码,可以发现工厂方法模式大大降低了对象之间的耦合度,这种依赖抽象的架构具有非常好的可扩展性
工厂方法模式的简单实现
好,上面只是简单讲解,下面来一个工厂方法的简单实现
这里我们以制作蛋糕为例
现在蛋糕店需要生产两种类型的蛋糕,分别是红色的草莓蛋糕和黄色的芒果蛋糕
因为蛋糕有着不同的制作材料和烘焙时间,所以在制作的过程中就需要区别对待了
那么了解了需求过后我们利用刚学的工厂方法模式来完成需求吧~
首先我们就可以定义一个蛋糕接口
public interface Cake {
/**
* 准备蛋糕的材料
*/
void prepareMaterials();
/**
* 烘焙蛋糕
*/
void baking();
}
好,现在该规划我们需要什么材料和烘焙的时间了的,对于草莓蛋糕,根据需求,我们的是草莓奶油并且需要烘焙15分钟
public class Strawberry implements Cake{
/**
* 草莓蛋糕需要准备草莓奶油
*/
@Override
public void prepareMaterials() {
System.out.println("prepare Strawberry Cream");
}
/**
* 草莓蛋糕需要烘焙15分钟
*/
@Override
public void baking() {
System.out.println("Baking fifteen minutes");
}
}
那么对于芒果蛋糕呢,我们需要的是芒果奶油的,需要烘焙10分钟
public class MangoCake implements Cake {
/**
* 芒果蛋糕需要准备芒果奶油
*/
@Override
public void prepareMaterials() {
System.out.println("prepare Mango Cream");
}
/**
* 芒果蛋糕需要烘焙10分钟
*/
@Override
public void baking() {
System.out.println("Baking ten minutes");
}
}
好了,具体的蛋糕制作流程都规划好了,下面是时候生产蛋糕了
要生产蛋糕,就需要工厂或者说作坊,那么为了规范我们的工厂该做什么,我们先定义一个抽象的工厂类,这里我们还是采用反射的方式,当然,如果你不喜欢用反射,那么你也可以定义普通的抽象方法,这些都是可以根据实际情况来决定的,没有硬性规定
public abstract class Factory {
public abstract <T extends Cake> T createProduct(Class<T> clz);
}
实现具体的工厂操作,让我们的工厂能够生产我们要的蛋糕
public class CakeFactory extends Factory {
@Override
public <T extends Cake> T createProduct(Class<T> clz) {
Cake cake = null;
try {
cake = (Cake) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) cake;
}
}
OK,蛋糕已经规划好了,工厂也造好了,万事俱备只欠东风,我们来测试一下(做蛋糕)~
public static void main(String[] args) {
/*创建蛋糕工厂*/
Factory factory = new CakeFactory();
/*制作草莓蛋糕*/
StrawberryCake strawberryCake = factory.createProduct(StrawberryCake.class);
strawberryCake.prepareMaterials();
strawberryCake.baking();
System.out.println();
/*制作芒果蛋糕*/
MangoCake mangoCake = factory.createProduct(MangoCake.class);
mangoCake.prepareMaterials();
mangoCake.baking();
}
Result:
prepare Strawberry Cream
Baking fifteen minutes
prepare Mango Cream
Baking ten minutes
大功告成~
END.