1、概述
工厂模式总结三个要点:
- 不想直接new这个类的对象,防止这个类改变的时候在new的地方到处去改,麻烦且容易遗漏;
- 这个类的对象构建过程非常复杂,不想在代码的各个地方将这么复杂的构建过程反复书写;
- 这个类的对象在构建过程中依赖了很多其他的类,而你无法在调用的地方提供。
2、结构
简单工厂包含如下角色:
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
3、背景
需求:设计一个披萨点餐系统。
设计一个披萨类(Pizza),并定义其两个子类(奶酪披萨【CheessPizza】和希腊披萨【GreekPizza】);再设计一个披萨店类(PizzaStore),披萨店具有点披萨的功能。
首先,我们先实现上述的需求。
//1.抽象产品
public abstract class Pizza
{
//名字
public string Name;
//准备原材料
public abstract void Prepare();
public void Bake()
{
Console.WriteLine($"{this.Name} bake");
}
public void Cut()
{
Console.WriteLine($"{this.Name} cut");
}
public void Box()
{
Console.WriteLine($"{this.Name} box");
}
}
//2.具体产品
public class CheessPizza : Pizza
{
public override void Prepare()
{
Console.WriteLine("CheessPizza 准备原材料");
}
}
//2.具体产品
public class GreekPizza : Pizza
{
public override void Prepare()
{
Console.WriteLine("GreekPizza 准备原材料");
}
}
//3.产品商店
public class PizzaStore
{
public static Pizza OrderPizza(string type)
{
Pizza pizza = null;
switch (type)
{
case "greek":
pizza = new GreekPizza();
pizza.Name = "希腊披萨";
break;
case "cheess":
pizza = new CheessPizza();
pizza.Name = "奶酪披萨";
break;
default:
break;
}
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
}
class Program
{
static void Main(string[] args)
{
PizzaStore.OrderPizza("greek");
PizzaStore.OrderPizza("cheess");
}
}
此时,如果我们要新增一个披萨商店,那个就需要增加一个【PizzaStore1】类;当我们要增加一款新的披萨产品(水果披萨【FruitPizza】)时, 我们要去修改每一个披萨商店的OrderPizza方法,也就是产品类和商店类耦合,违反了开闭原则(对于扩展是开放的,但是对于修改是封闭的);
那么有没有办法将产品类和商店类解耦呢?答案是有的,就是引入工厂模式。
4、简单工厂模式
我们首先引入简单工厂,
//具体工厂
public class PizzaSimpleFactory
{
public static Pizza CreatPizza(string type)
{
Pizza pizza = null;
switch (type)
{
case "greek":
pizza = new GreekPizza();
pizza.Name = "希腊披萨";
break;
case "cheess":
pizza = new CheessPizza();
pizza.Name = "奶酪披萨";
break;
default:
break;
}
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
}
//产品商店
public class PizzaStore
{
public static Pizza OrderPizza(string type)
{
Pizza pizza = PizzaSimpleFactory.CreatPizza(type);
return pizza;
}
}
可以看出,简单工厂模式的出现,使得我们通过传入不同的参数类型就可以创建不同类型的对象实例,将对象的构建过程完全交给了简单工厂方法类SimpleFactory。我们要增加一款新的披萨产品(水果披萨【FruitPizza】)时,只需要修改【PizzaSimpleFactory】。
一旦有了PizzaSimpleFactory,PizzaStore类中的OrderPizza()就变成此对象的客户,后期如果需要Pizza对象直接从工厂中获取即可。这样也就解除了和Pizza实现类的耦合,同时又产生了新的耦合,PizzaStore对象和SimplePizzaFactory工厂对象的耦合,工厂对象和商品对象的耦合。
但是,后期如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的代码,违反了开闭原则。
5、简单工厂模式的缺点
优点:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,同样违背了“开闭原则”。
为了克服简单工厂模式的缺点,工厂方法模式就被提了出来,我们下篇文章再介绍。