一、什么是抽象工厂模式
提供一个接口创建一组或一系列相关或互相依赖的对象
抽象工厂主要是针对种类繁多,需要一系列的对象组合的情况,而每次只需要实例其中的一组系列。是工厂模式的升级,进一步抽象,工厂模式只能生产一个等级的产品,而抽象工厂能生产多个等级的一个系列的产品。
UML图
AbstractFactory: 抽象工厂,定义一系列有关联的接口
ConcreteFactory:实现具体的接口对象,实现不同级别的产品组合.
AbstractProduct: 抽象产品,定义一个级别的产品,多个抽象产品分别定义不同级别的产品
二、适用场景
每一系列产品具有不同级别的产品,比如格力系列家电,空调/洗衣机/冰箱, 海尔系列家电,空调/洗衣机/冰箱。 空调和空调就是同一级别的产品, 空调、洗衣机、冰箱就是不同级别的产品,但是又可以属于同一品牌,具有关联性。
当需要创建的对象是一些列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。也就是说一个继承体系中,如果存在着多个等级结构(相当于多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更适合一点。
三、优缺点
优点
在内部对产品族进行约束,同一个产品族之间的产品应具备某些关联
在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
当增加一个新的产品族时,不需要修改代码。
缺点
当需要增加一个新的产品时,所有的工厂类都需要修改
四、大话中的例子
各种数据库的实现是sql还是 accesst ,每一类数据库里面又包含不同级别的内容,比如用户名、依赖文件。有一个抽象工厂类里面定义 用户名、依赖文件的方法, 具体的sql工厂方法则实现 sql的用户名, sql的依赖文件, 具体的accesst工厂方法则实现accesst的用户名,accesst的依赖方法。
五、我的例子
抽象工厂模式
using System;
namespace AbstractFactory
{
class Program
{
static void Main(string[] args)
{
NinjaTeam ninjaTeam = new KonohaVillage();
//NinjaTeam ninjaTeam = new SandVillage();
ninjaTeam.AddDpsNinja().TaskDamage(99);
ninjaTeam.AddMedicalNinja().Iatrotechnics(50);
ninjaTeam.AddTrackNinja().TrackPos();
Console.ReadKey();
}
}
/// <summary>
/// 忍者
/// </summary>
public abstract class Ninja
{
string name;
public string Name { get { return name; } }
public Ninja(string name)
{
this.name = name;
}
}
/// <summary>
/// 医疗忍者
/// </summary>
public abstract class MedicalNinja : Ninja
{
public MedicalNinja(string name) : base(name)
{
}
/// <summary>
/// 治疗术
/// </summary>
/// <param name="ninja"></param>
public void Iatrotechnics(int hp)
{
Console.WriteLine("{0}为队友恢复生命值{1}点", Name, hp);
}
}
/// <summary>
/// 追踪忍者
/// </summary>
public abstract class TrackNinja : Ninja
{
public TrackNinja(string name) : base(name)
{
}
/// <summary>
/// 追踪术
/// </summary>
public void TrackPos()
{
Console.WriteLine("{0}在追纵敌人的踪迹", Name);
}
}
/// <summary>
/// 输出忍者
/// </summary>
public abstract class DpsNinja : Ninja
{
public DpsNinja(string name) : base(name)
{
}
/// <summary>
/// 输出
/// </summary>
/// <param name="damage"></param>
public void TaskDamage(int damage)
{
Console.WriteLine("{1}对敌人造成{0}点伤害", damage, Name);
}
}
/// <summary>
/// 小樱
/// </summary>
public class Sakura : MedicalNinja
{
public Sakura(string name) : base(name)
{
}
}
/// <summary>
/// 佐井
/// </summary>
public class Sai : TrackNinja
{
public Sai(string name) : base(name)
{
}
}
/// <summary>
/// 鸣人
/// </summary>
public class Naruto : DpsNinja
{
public Naruto(string name) : base(name)
{
}
}
/// <summary>
/// 手鞠
/// </summary>
public class Temari : MedicalNinja
{
public Temari(string name) : base(name)
{
}
}
/// <summary>
/// 勘九郎
/// </summary>
public class Kankuro : TrackNinja
{
public Kankuro(string name) : base(name)
{
}
}
/// <summary>
/// 我爱罗
/// </summary>
public class Gaara : DpsNinja
{
public Gaara(string name) : base(name)
{
}
}
/// <summary>
/// 忍者小队三人组
/// </summary>
public abstract class NinjaTeam
{
public abstract MedicalNinja AddMedicalNinja();
public abstract TrackNinja AddTrackNinja();
public abstract DpsNinja AddDpsNinja();
}
/// <summary>
/// 木叶村小队
/// </summary>
public class KonohaVillage : NinjaTeam
{
public override DpsNinja AddDpsNinja()
{
return new Naruto("鸣人");
}
public override MedicalNinja AddMedicalNinja()
{
return new Sakura("小樱");
}
public override TrackNinja AddTrackNinja()
{
return new Sai("佐井");
}
}
/// <summary>
/// 砂隐村小队
/// </summary>
public class SandVillage : NinjaTeam
{
public override DpsNinja AddDpsNinja()
{
return new Gaara("我爱罗");
}
public override MedicalNinja AddMedicalNinja()
{
return new Temari("手鞠");
}
public override TrackNinja AddTrackNinja()
{
return new Kankuro("勘九郎");
}
}
}
运行结果
把木叶小队换成砂隐小队,只需要把NinjaTeam ninjaTeam = new KonohaVillage(); 更改为NinjaTeam ninjaTeam = new SandVillage();其它都不用变。
运行结果
抽象工厂结合简单工厂
只需要将上述的NinjaTeam SandVillage KonohaVillage 这三个类用一个简单工厂类代替,不同系列用 switch区分.
public class DataAccess
{
// string VillageName = "konoha";
string VillageName = "sand";
public MedicalNinja AddMedicalNinja()
{
MedicalNinja medicalNinja = null; ;
switch (VillageName)
{
case "konoha":
medicalNinja = new Sakura("小樱");
break;
case "sand":
medicalNinja = new Temari("手鞠");
break;
}
return medicalNinja;
}
public TrackNinja AddTrackNinja()
{
TrackNinja trackNinja = null;
switch (VillageName)
{
case "konoha":
trackNinja = new Sai("佐井");
break;
case "sand":
trackNinja = new Kankuro("勘九郎");
break;
}
return trackNinja;
}
public DpsNinja AddDpsNinja()
{
DpsNinja dpsNinja = null;
switch (VillageName)
{
case "konoha":
dpsNinja = new Naruto("鸣人");
break;
case "sand":
dpsNinja = new Gaara("我爱罗");
break;
}
return dpsNinja;
}
}
抽象工厂结合简单工厂结合反射
using System;
using System.Reflection;
namespace AbstractFactory
{
class Program
{
static void Main(string[] args)
{
ReflectDataAccess reflectDataAccess = new ReflectDataAccess();
DpsNinja dpsNinja = reflectDataAccess.AddDpsNinja();
dpsNinja.TaskDamage(78);
reflectDataAccess.AddMedicalNinja().Iatrotechnics(30);
Console.ReadKey();
}
}
public class SandMedical : MedicalNinja
{
public SandMedical(string name) : base(name)
{
}
public SandMedical() { Name = "千代婆婆"; }
}
public class SandDps : DpsNinja
{
public SandDps()
{
Name = "赤砂之蝎";
}
public SandDps(string name) : base(name)
{
}
}
public class KonohaMedical : MedicalNinja
{
public KonohaMedical()
{
Name = "纲手";
}
public KonohaMedical(string name) : base(name)
{
}
}
public class KonohaDps : DpsNinja
{
public KonohaDps()
{
Name = "自来也";
}
public KonohaDps(string name) : base(name)
{
}
}
public enum EVillageName
{
Sand,
Konoha,
}
/// <summary>
/// 利用反射性质的简单工厂
/// </summary>
public class ReflectDataAccess
{
private static readonly string AssemblyName = "AbstractFactory";//程序集名
private static readonly string VillageName = EVillageName.Konoha.ToString(); //限制名
public MedicalNinja AddMedicalNinja()
{
string className = AssemblyName + "." + VillageName + "Medical";//类的完整名
object[] obj = new object[1];
obj[0] = "大哥";
return (MedicalNinja)Assembly.Load(AssemblyName).CreateInstance(className);//用类名字符串返回一个类对象
//return (MedicalNinja)Assembly.Load(AssemblyName).CreateInstance(className, true, BindingFlags.Default, null, obj, null, null);//带参构造函数的使用
}
public DpsNinja AddDpsNinja()
{
string className = AssemblyName + "." + VillageName + "Dps";
return (DpsNinja)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
}
运行结果
将 private static readonly string VillageName = EVillageName.Konoha.ToString(); //限制名
改为 private static readonly string VillageName = EVillageName.Sand.ToString(); //限制名
运行结果
PS:抽象工厂模式的使用非常具有针对性,适用于产品族丰富,产品等级确定无变化的情况,增加族群只需要增加相应的具体族群工厂,每一个抽象等级产品下派生该族群的产品即可,只需要添加类,不需要修改,但如果要添加某一产品,那需要改动的就太多了, 抽象工厂类/具体工厂类/都要修改,还要增加抽象等级产品。 结合简单工厂模式能部分避免一些问题,但依旧显得繁琐。再结合反射的原理,可以大大节约简单工厂中的 条件分支语句。如果是针对抽象工厂的衍生,在具体产品类起名字的时候就得非常注意规整性,否则使用反射就很难控制, 而只是单纯的简单工厂就没有这个顾虑了。