定义一个可以产生对象的接口,但是让子类决定要产生哪一个类的对象。工厂方法模式让类的实例化程序延迟到子类中实施。
工厂模式,顾名思义,主要用在“大量生产某个东西”的地方,并且是有组织,有规律的进行生产。在程序开发中,会遇到大量生成某个对象的情况。比如游戏中,需要生成若干敌人,这些敌人既可以是相同的,也可以是有差别的,像模型,属性等。如果每次生成的时候,都对其进行手动初始化,改下属性啦,位置什么的,肯定很麻烦,还容易出错~
那么有没有一种可以将这些生成行为规范化的方法呢?
那就是工厂模式~
简单工厂模式
举个栗子,巧克力和香子兰肚子饿了,她们要吃好吃的。巧克力说她要吃蛋糕,香子兰说她只要一杯奶茶就够了。以编程的角度看,我们需要生成蛋糕和奶茶。常规思路代码如下:
首先定义蛋糕类和奶茶类;
public class Cake
{
public Cake()
{
Console.WriteLine("生成蛋糕。");
}
}
public class MilkTea
{
public MilkTea()
{
Console.WriteLine("生成奶茶。");
}
} 然后在Main方法里生成;
public static void Main(string[] args)
{
string str = Console.ReadLine();
Cake cake;
MilkTea milkTea;
if (str == "蛋糕")
{
cake = new Cake();
}
else if (str == "奶茶")
{
milkTea = new MilkTea();
}
} 可以看到,这样的代码存在不小的问题,首先是即便是生成一种,我们也要把其他所有食物进行声明,不然无法获得引用,当然这个可以通过定义一个食物父类来解决。另外如果要增加别的食物,需要修改main方法。如果食物种类少了还好,但是当达到成百上千时,结构会非常臃肿,而且违反了开闭原则。
接下来我们使用简单工厂模式改写下:
首先定义一个食物基类Food,并让蛋糕和奶茶继承:
public abstract class Food
{
}
public class Cake : Food
{
public Cake()
{
Console.WriteLine("生成蛋糕。");
}
}
public class MilkTea : Food
{
public MilkTea()
{
Console.WriteLine("生成奶茶。");
}
} 然后定义工厂类用来产生食物:
public class FoodFactory
{
public Food CreateFood(string foodName)
{
if (String.IsNullOrEmpty(foodName))
{
return null;
}
Food food = null;
switch (foodName)
{
case "蛋糕":
food = new Cake();
break;
case "奶茶":
food = new MilkTea();
break;
default:
break;
}
return food;
}
} 最后在Main方法里调用:
public static void Main(string[] args)
{
FoodFactory factory = new FoodFactory();
string str = Console.ReadLine();
Food food = factory.CreateFood(str);
} 可以看到,这次Main方法简洁了许多,通过使用简单工厂模式,成功的将“生成”和“使用”进行分离,极大的降低了耦合度。前台只需要知道通过传参获得想要的对象就够了。至于怎么生成那是后台工厂类的事。之后如果想增加新的食物,只需要改一下新建一个类并继承自Food,再switch里的参数就行了。
工厂方法模式
看过了简单工厂模式,是不是觉得已经没问题了呢?然而以上只是为了演示,并没有多少功能性的代码。试想一下,在实际开发中,如果需要很多与对象创建有关的代码,而且需要创建很多对象,是不是意味着要在这个简单工厂类里编写很多方法。比如说蛋糕要调整大小,奶茶要调整甜度等等。这样的话每次都需要打开这个简单工厂类进行修改。。
接下来研究工厂方法模式:向上代码:
这次对工厂类进行了抽象:
public interface IFoodFactory
{
Food Create();
}
public class CakeFactory : IFoodFactory
{
public Food Create()
{
return new Cake();
}
}
public class MilkTeaFactory : IFoodFactory
{
public Food Create()
{
return new MilkTea();
}
} Main里调用,这次取消了判断代码。
public static void Main(string[] args)
{
IFoodFactory cakeFactory = new CakeFactory();
IFoodFactory milkFactory = new MilkTeaFactory();
Food cake = cakeFactory.Create();
Food milkTea = milkFactory.Create();
} 这个模式是对简单工厂模式的解耦,在工厂方法模式中一个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口。相当于把原来的一个简单工厂类进行了拆分。降低了耦合度。
抽象工厂模式
其实绝大多数情况下使用以上的模式就可以了,不过还有种情况,巧克力除了要吃蛋糕还要喝奶茶,香子兰除了喝奶茶还要吃蛋糕。这种情况利用上面的方法也不是不可以,可以如果她们还要冰淇淋,饼干,薯片等等一大堆的东西呢。总不能在main方法里写一大堆调用方法吧。
接下来介绍另一种工厂模式:抽象工厂模式。先上代码:
这次对工厂和单个种类的食物进行了抽象~
public abstract class Cake
{
}
public class StrawberryCake : Cake
{
public StrawberryCake()
{
Console.WriteLine("生成草莓蛋糕。");
}
}
public abstract class MilkTea
{
}
public class RedBeanMilkTea : MilkTea
{
public RedBeanMilkTea()
{
Console.WriteLine("生成红豆奶茶。");
}
} 将巧克力与香子兰当做工厂:
public abstract class IFoodFactory
{
public abstract Cake CreateCake();
public abstract MilkTea CreateMilkTea();
public virtual void Create()
{
CreateCake();
CreateMilkTea();
}
}
/// <summary>
/// 巧克力。
/// </summary>
public class ChocolatFactory : IFoodFactory
{
public override Cake CreateCake()
{
// 此处可以增加条件,生成不同的对象
return new StrawberryCake();
}
public override MilkTea CreateMilkTea()
{
// 此处可以增加条件,生成不同的对象
return new RedBeanMilkTea();
}
}
/// <summary>
/// 香子兰
/// </summary>
public class VanillaFactory : IFoodFactory
{
public override Cake CreateCake()
{
// 此处可以增加条件,生成不同的对象
return new StrawberryCake();
}
public override MilkTea CreateMilkTea()
{
// 此处可以增加条件,生成不同的对象
return new RedBeanMilkTea();
}
} 然后调用:
public static void Main(string[] args)
{
IFoodFactory chocolat = new ChocolatFactory();
IFoodFactory vanilla = new VanillaFactory();
chocolat.Create();
vanilla.Create();
} 


3 comments
👿 写的有点仓促,如有不足之处还请指出~
奈飞🐮🍺 :exclaim:
👿 嘘~