简单工厂模式
简单工厂模式,指将一些对象的创建从由使用者进行创建,改为由一个工厂类来统一创建对象,使用者只需要传入对应的参数告知工厂类需要哪一种对象即可。
这里以餐厅为例,餐厅后厨负责做菜,服务员充当工厂角色,用来传递顾客的点餐给后厨,后厨做完之后由服务员传递
首先需要定义一个后厨接口,用于服务员(工厂)创建餐品(对象)
public interface Cooker {
public void cook();
}
然后定义三种菜品类继承后厨接口
public class Fish implements Cooker{
@Override
public void cook() {
System.out.println("一份酸菜鱼");
}
}
public class Meat implements Cooker{
@Override
public void cook() {
System.out.println("一份小炒肉");
}
}
public class Vegetable implements Cooker{
@Override
public void cook() {
System.out.println("一份手撕包菜");
}
}
最后定义一个服务员类(工厂类),用于点餐
public class RestaurantFactory {
public static final int FISH=1;
public static final int MEAT=2;
public static final int VEGETABLE=3;
//点菜
public Cooker getCook(int cookName)
{
switch (cookName)
{
case FISH:
return new Fish();
case MEAT:
return new Meat();
case VEGETABLE:
return new Vegetable();
default:
return null;
}
}
}
测试用户点餐
public class FactoryTest {
@Test
public void simpleFactoryTest()
{
//获取工厂实例,类似服务员
RestaurantFactory restaurantFactory = new RestaurantFactory();
Cooker cooker = restaurantFactory.getCook(RestaurantFactory.FISH);
cooker.cook();
}
}
点餐结果
一份酸菜鱼
工厂方法模式
简单工厂方法有以下几个问题
- 工厂类负责创建所有的类,如果工厂类出现问题则整个系统出现问题
- 新增加新产品就需要在工厂类中修改逻辑
- 过多的产品会导致工厂类代码过于复杂
所以在业务复杂时,提出了工厂方法模式。将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
这里以餐厅发展分店为例,其中每一个分店都可能有自己的特色产品,所有每一个分店都会有一个自己的工厂类。而我们将总店的工厂类变为抽象类,具体的菜品生成实现由各个分店工厂类自行实现。
总店的工厂类
public abstract class RestaurantFactory {
//点菜
public abstract Cooker getCook(int cookName);
}
餐厅A的工厂类,需继承总店工厂类
public class RestaurantA extends RestaurantFactory{
public static final int FISH=1;
public static final int MEAT=2;
//点菜
public Cooker getCook(int cookName)
{
switch (cookName)
{
case FISH:
return new Fish();
case MEAT:
return new Meat();
default:
return null;
}
}
}
餐厅B工厂类
public class RestaurantB extends RestaurantFactory{
public static final int MEAT=2;
public static final int VEGETABLE=3;
//点菜
public Cooker getCook(int cookName)
{
switch (cookName)
{
case MEAT:
return new Meat();
case VEGETABLE:
return new Vegetable();
default:
return null;
}
}
}
测试类
@Test
public void simpleFactoryTest()
{
//获取工厂实例,类似服务员
RestaurantFactory restaurantFactoryA = new RestaurantA();
Cooker cookerA = restaurantFactoryA.getCook(RestaurantA.FISH);
cookerA.cook();
RestaurantFactory restaurantFactoryB = new RestaurantB();
Cooker cookerB = restaurantFactoryB.getCook(RestaurantB.MEAT);
cookerB.cook();
}
测试结果
一份酸菜鱼
一份小炒
抽象工厂模式
抽线工厂模式则是对工厂方法模式的最上层维度进行进一步的扩展,主要用于解决将产品分为多个产品族,每一个产品族都交由对应的工厂负责。
以经营餐厅的例子来说。这里我引入美团外卖来作为最上层的抽象工厂,美团外卖中可能会有不同的业务(产品族),然后每个业务都有自己的产品类,业务中也会有不同的品牌,品牌有自己的产品及工厂
具体例子
美团外卖中存在外卖点餐业务,其中可以点餐的餐厅有餐厅A与餐厅B,两者分别有两个不同的菜。
点餐业务(产品族)抽象类
public abstract class Eat {
public abstract void cook();
}
有两家餐厅,A与B
//A品牌店
public abstract class RestaurantTypeA extends Eat{
}
//B品牌店
public abstract class RestaurantTypeB extends Eat{
}
餐厅A的菜品有鱼和肉
public class AFIsh extends RestaurantTypeA {
@Override
public void cook() {
System.out.println("用户点了A餐厅的酸菜鱼");
}
}
public class AMeat extends RestaurantTypeA {
@Override
public void cook() {
System.out.println("用户点了A餐厅的小炒肉");
}
}
餐厅B的菜品有鱼和蔬菜
public class BFish extends RestaurantTypeB {
@Override
public void cook() {
System.out.println("用户点了B餐厅的红烧鲈鱼");
}
}
public class BVegetable extends RestaurantTypeB {
@Override
public void cook() {
System.out.println("用户点了B餐厅的白灼菜心");
}
}
然后是对应的工厂类,用来创建产品族产品
首先是抽象工厂类
//最高级抽象工厂,美团
public abstract class MeiTuan {
public abstract Eat getCook(String cookName) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
品牌A的工厂类
public class RestaurantFactoryA extends MeiTuan {
@Override
public Eat getCook(String cookName) throws ClassNotFoundException,
IllegalAccessException, InstantiationException{
Class dish=Class.forName(cookName);
return (RestaurantTypeA)dish.newInstance();
}
}
品牌B的工厂类
public class RestaurantFactoryB extends MeiTuan {
@Override
public Eat getCook(String cookName) throws ClassNotFoundException,
IllegalAccessException, InstantiationException{
Class dish=Class.forName(cookName);
return (RestaurantTypeB)dish.newInstance();
}
}
超级工厂类,用来创建工厂的类
public class FactoryProducer {
public static MeiTuan getFactory(String name) throws IllegalAccessException, InstantiationException, ClassNotFoundException
{
Class cl = Class.forName(name);
System.out.println("创建工厂"+name);
return (MeiTuan)cl.newInstance();
}
}
测试用例
@Test
public void abstractFactoryTest()throws IllegalAccessException,
InstantiationException, ClassNotFoundException
{
//获取工厂(餐厅)实例
MeiTuan factory = FactoryProducer.getFactory("com.java.design.dal.po.factory.RestaurantFactoryA");
Eat ADish = factory.getCook("com.java.design.dal.po.factory.AFIsh");
ADish.cook();
Eat ADish1 = factory.getCook("com.java.design.dal.po.factory.AMeat");
ADish1.cook();
MeiTuan factory1 = FactoryProducer.getFactory("com.java.design.dal.po.factory.RestaurantFactoryB");
Eat BDish = factory1.getCook("com.java.design.dal.po.factory.BFish");
BDish.cook();
Eat BDish1 = factory1.getCook("com.java.design.dal.po.factory.BVegetable");
BDish1.cook();
}
测试结果
创建工厂com.java.design.dal.po.factory.RestaurantFactoryA
用户点了A餐厅的酸菜鱼
用户点了A餐厅的小炒肉
创建工厂com.java.design.dal.po.factory.RestaurantFactoryB
用户点了B餐厅的红烧鲈鱼
用户点了B餐厅的白灼菜心
可以看出来,抽象工厂中可能会有多个产品族(我这里只举了一个),然后每个产品族会有对应的工厂去生产。