工厂方法模式
文章目录
- 工厂方法模式
- 工厂方法模式是什么
- 理解工厂方法模式
- 代码实例
- 运行截图
- 工厂方法的优点
- 工厂方法的不足
工厂方法模式是什么
- 工厂方法模式
属于创建型模式
,也叫抽象构造模式, 工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。
理解工厂方法模式
- 这种模式是在原先的层级上多加了一层 实现的效果就是,不由原先的工厂类来实例对象工厂父类来定义创建产品的公共接口, 而各工厂子类对象通过集成来实现这个创建接口, 在这个实现里面去完成究竟应该实例化哪一个具体产品,这样就可以在不影响原先种类的情况下引入新的产品。
代码实例
- 在这个代码实例中,我们将模拟订购pizza的场景,这次我们加入风味元素,如有北京风味的芝士披萨、伦敦风味的牛肉披萨等。
- 我们先定义各种产品类,他们有一个抽象父类,如Pizza类,具体产品类都继承自他
- 然后创建一个抽象工厂类,在这个抽象工厂种定义一个抽象的创建方法,后续让子类去实现
- 创建多种具体实现创建接口的实现类,在实现类中来决定具体创建哪一个pizza类
- 创建订购类,在这个类中实现各种方法的调用
/**
* 这种模式是在原先的层级上多加了一层
* 实现的效果就是,不由原先的工厂类来实例对象
* 工厂父类来定义创建产品的公共接口,
* 而各工厂子类对象通过集成来实现这个创建接口,
* 在这个实现里面去完成究竟应该实例化哪一个具体产品
* 这样就可以在不影响原先种类的情况下引入新的产品
*/
import java.util.Scanner;
public class 工厂方法 {
public static void main(String[] args) {
new Order().buy();
}
}
//定义一个购买订单
class Order {
public void buy() {
Scanner in = new Scanner(System.in);
while (true) {
System.out.print("您需要什么地方的pizza:");
String address = in.nextLine();
PizzaFactory factory = null;
if ("bj".equals(address)) {
factory = new BjPizzaFactory();
} else if ("ld".equals(address)) {
factory = new LDPizzaFactory();
}else {
System.out.println("没有这个地方的口味哦");
continue;
}
System.out.print("您需要什么口味的pizza:");
String type = in.nextLine();
Pizza pizza = factory.createPizza(type);
System.out.println("订单需要为:" + pizza.pizzaName + " " + pizza);
if (pizza != null) {
pizza.material();
pizza.bake();
pizza.cut();
pizza.box();
}
}
}
}
//定义一个pizza创建工厂类
abstract class PizzaFactory {
abstract public Pizza createPizza(String pizzaType);
}
class BjPizzaFactory extends PizzaFactory {
@Override
public Pizza createPizza(String type) {
if (type.equals("cheese")) {
return new BjCheesePizza("芝士");
} else if (type.equals("beef")) {
return new BjBeefPizza("牛肉");
} else {
System.out.println("没有此类型的pizza");
return null;
}
}
}
class LDPizzaFactory extends PizzaFactory {
@Override
public Pizza createPizza(String type) {
if (type.equals("cheese")) {
return new LDCheesePizza("芝士");
} else if (type.equals("beef")) {
return new LDBeefPizza("牛肉");
} else {
System.out.println("没有此类型的pizza");
return null;
}
}
}
abstract class Pizza {
String pizzaName;
Pizza(String pizzaName) {
this.pizzaName = pizzaName + "披萨";
}
//准备材料
abstract public void material();
void bake() {
System.out.println("正在烤 " + this.pizzaName);
}
void cut() {
System.out.println("正在切 " + this.pizzaName);
}
void box() {
System.out.println("正在打包 " + this.pizzaName);
}
}
//利用多个披萨类来继承
class BjCheesePizza extends Pizza {
BjCheesePizza(String pizzaName) {
super(pizzaName);
}
@Override
public void material() {
System.out.println("正在准备北京芝士披萨的材料");
}
}
class BjBeefPizza extends Pizza {
BjBeefPizza(String pizzaName) {
super(pizzaName);
}
@Override
public void material() {
System.out.println("正在准备北京牛肉披萨的材料");
}
}
class LDCheesePizza extends Pizza {
LDCheesePizza(String pizzaName) {
super(pizzaName);
}
@Override
public void material() {
System.out.println("正在准备伦敦芝士披萨的材料");
}
}
class LDBeefPizza extends Pizza {
LDBeefPizza(String pizzaName) {
super(pizzaName);
}
@Override
public void material() {
System.out.println("正在准备伦敦牛肉披萨的材料");
}
}
运行截图
工厂方法的优点
- 不关心创建细节: 用户只需要关心产品所对应的工厂,不需要关心它内部是如何创建
- 符合开闭原则: 加入新的产品,只需要增加新的工厂类就可以,符合开闭原则,提高了可扩展性
工厂方法的不足
- 增加了代码的复杂性: 因为需要增加具体工厂类,所以
类的个数容易过多,增加了系统的复杂度
(除了编写新的产品类之外,还要编写该产品类的对应工厂类)。 - 增加难度:
增加了系统的抽象性和理解难度
(工厂方法本身利用了抽象,该模式中会引入抽象层,如果需要动态创建产品类,还需要引入反射技术)。
设计模式的使用 , 要根据实际的业务场景 , 模型综合平衡考量 , 不能过分遵守设计原则 和 设计模式