工厂模式(Factory Pattern)
简单工厂
又叫做静态工厂方法(Static Factory Method)模式,但不属于 23 种设计模式之一。 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
例子
张三准备自主创业,想开一个餐厅,由于前期资金有限只能请一个厨师,假定只出售红烧肉和土豆丝。代码如下
package com.itxiaoer.simple;
/**
* 食物
*
* @author : liuyk
*/
public interface Food {
/**
* 名称
*/
void name();
}
package com.itxiaoer.simple;
/**
* 土豆丝
*
* @author : liuyk
*/
public class PotatoSilk implements Food {
@Override
public void name() {
System.out.println("您点了土豆丝");
}
}
package com.itxiaoer.simple;
/**
* 红烧肉
*
* @author : liuyk
*/
public class RedCookedPork implements Food {
@Override
public void name() {
System.out.println("您点了红烧肉");
}
}
package com.itxiaoer.simple;
/**
* 食物工程类
*
* @author : liuyk
*/
public class FoodFactory {
public static Food create(String type) {
switch (type) {
case "土豆丝":
return new PotatoSilk();
case "红烧肉":
return new RedCookedPork();
default:
throw new IllegalArgumentException(" type error");
}
}
}
package com.itxiaoer.simple;
import org.junit.Test;
public class TestFoodFactory {
@Test
public void create() {
// 顾客想吃土豆丝
FoodFactory.create("土豆丝").name();
// 顾客想吃红烧肉
FoodFactory.create("红烧肉").name();
}
}
缺点
- 由于工厂类(厨师)集中了所有产品的创建逻辑,一旦不能正常工作(厨师生病),将影响整个系统(餐厅)。
- 系统(增加菜品)扩展困难,一旦添加新产品就必须要修改工厂逻辑(厨师需要进修),在产品类型比较多的时候,工厂逻辑比较复杂,不利于系统的扩展和维护(学习成本高)。
- 简单工厂会一定程度上增加系统的类的数量,一定程度上增加系统的复杂度和理解难度。
使用场景
- 工厂创建的类比较少,由于创建的类比较少,不会造成工厂业务过于复杂。
- 客服端只知道工厂类型的参数,对于如何创建对象并不关心,不需要关心创建细节,甚至类名都不需要记住,只需知道类型参数。
工厂方法
工厂方法是针对每一种产品提供一个工厂类, 通过不同的工厂实例来创建不同的产品实例。
例子
张三经营了一段时间,顾客慢慢增多,一个厨师忙不过来了,于是又请了一个厨师,张三决定让一个厨师炒土豆丝,一个厨师炒红烧肉。
package com.itxiaoer.method;
/**
* 食物
*
* @author : liuyk
*/
public interface Food {
/**
* 名称
*/
void name();
}
package com.itxiaoer.method;
/**
* 土豆丝
*
* @author : liuyk
*/
public class PotatoSilk implements Food {
@Override
public void name() {
System.out.println("您点了土豆丝");
}
}
package com.itxiaoer.method;
/**
* 红烧肉
*
* @author : liuyk
*/
public class RedCookedPork implements Food {
@Override
public void name() {
System.out.println("您点了红烧肉");
}
}
package com.itxiaoer.method;
/**
* 食物工厂类(厨师)
*
* @author : liuyk
*/
public interface FoodFactory {
/**
* 创建
*
* @return 食物
*/
Food create();
}
package com.itxiaoer.method;
/**
* 土豆丝工厂类
*
* @author : liuyk
*/
public class PotatoSilkFactory implements FoodFactory {
@Override
public Food create() {
return new PotatoSilk();
}
}
package com.itxiaoer.method;
/**
* 红烧肉工厂类
*
* @author : liuyk
*/
public class RedCookedPorkFactory implements FoodFactory {
@Override
public Food create() {
return new RedCookedPork();
}
}
package com.itxiaoer.method;
import org.junit.Test;
public class TestFoodFactory {
@Test
public void create() {
// 顾客想吃土豆丝
new PotatoSilkFactory().create().name();
// 顾客想吃红烧肉
new RedCookedPorkFactory().create().name();
}
}
缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 一个具体工厂只能创建一种具体产品
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
优点
- 扩展容易,新增一种新产品时,只需要增加对应的产品和工厂类即可,无需修改原有代码
- 职责单一,每个工厂只负责一个产品的创建
使用场景
- 当一个类不知道它所需要的对象的类时
在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可; *当一个类希望通过其子类来指定创建对象时
在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。