上篇将工厂模式讲完了,这次我们来说说抽象工厂模式,如果说工厂模式是生产一种东西,简单工厂模式是参数化的工厂模式,那么抽象工厂模式是生产一类东西。我们不一定要找他们不同的地方,找相同的地方也一样会更加理解。这个模板化的抽象工厂模式UML图比较难画,关键代码也是和工厂长的差不多。这里我们从例子中总结出它的 UML图模板,然后在分析它的关键代码。
这里软件环境是 Unity2017


抽象工厂模式

  1. 意图:让工厂模式不仅可以生产一种东西,还可以生产一类东西。或者说从不同公司/渠道生产一种东西。
  2. 如何使用:提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
  3. 例子
    (1).大话设计模式上的例子
    UML图:

    这里上面两个类的关系没画,在画就太乱了,但是他们是有依赖关系的。
    客户端类,工厂表接口与实现类
public class AbstractFactorBook : MonoBehaviour
{
    void Start()
    {
        User user = new User();
        Department dept = new Department();
        //
        IFactorys factory = new AccessFactory();
        IUser iu = factory.CreateUser();
        iu.Insert(user);
        iu.GetUser(1);
        //
        IDepartment id = factory.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);
    }
}
interface IFactorys
{
    IUser CreateUser();
    IDepartment CreateDepartment();
}
class SqlServerFactory : IFactorys
{
    public IDepartment CreateDepartment()
    {
        return new SqlserverDepartment();
    }

    public IUser CreateUser()
    {
        return new SqlserverUser();
    }
}
class AccessFactory : IFactorys
{
    public IDepartment CreateDepartment()
    {
        return new AccessDepartment();
    }
    public IUser CreateUser()
    {
        return new AccessUser();
    }
}

用户表和部门表接口与实现类

interface IDepartment
{
    void Insert(Department department);
    Department GetDepartment(int id);
}
class SqlserverDepartment : IDepartment
{
    public Department GetDepartment(int id)
    {
        Debug.Log("在SQL Server中根据ID得到Department表一条记录");
        return null;
    }
    public void Insert(Department department)
    {
        Debug.Log("在SQL Server中给Department表增加一条记录");
    }
}
class AccessDepartment : IDepartment
{
    public Department GetDepartment(int id)
    {
        Debug.Log("在Access中根据ID得到Department表记录一条记录");
        return null;
    }
    public void Insert(Department department)
    {
        Debug.Log("在Access中给Department表增加一条记录");
    }
}
interface IUser
{
    void Insert(User user);
    User GetUser(int id);
}
class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在SQL Server中给User表增加一条记录");
    }
    public User GetUser(int id)
    {
        Debug.Log("在SQL Server中根据ID得到User表一条记录");
        return null;
    }
}
class AccessUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在Access中给User表增加一条记录");
    }
    public User GetUser(int id)
    {
        Debug.Log("在Access中根据ID得到User表一条记录");
        return null;
    }
}

用户表和部门表

//用户
class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }
    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}
//部门
class Department
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }
}

(2)菜鸟教程上的例子

UML图:

java抽象工厂举例 抽象工厂 uml_java抽象工厂举例


代码:

客户端代码

public class AbstractFactorPattern : MonoBehaviour
{
    void Start()
    {
        AbstractFactory shapeFactory = FactoryProducer.GetFactory("SHAPE");
        IShape shape = shapeFactory.GetShape("CIRCLE");
        shape.Draw();
    }
}

绘制图形颜色接口与实现

public interface IShape
{
    void Draw();
}
public class Rectangle : IShape
{
   public void Draw()
   {
    Debug.Log("绘制Rectangle(矩形)");
   }
}
public class Circle : IShape
{
  public void Draw()
  {
    Debug.Log("绘制Circle(圆形)");
  }
}
public class Square : IShape
{
  public void Draw()
  {
    Debug.Log("绘制Square(正方形)");
  }
}
public interface IColor
{
    void Fill();
}
public class Red : IColor
{
  public void Fill()
  {
    Debug.Log("绘制Red");
  }
}
public class Green : IColor
{
  public void Fill()
  {
    Debug.Log("绘制Green");
  }
}
public class Blue : IColor
{
    public void Fill()
    {
    Debug.Log("绘制Blue");
    }
}

工厂类接口和它的子类

public abstract class AbstractFactory
{
    public abstract IColor GetColor(string color);
    public abstract IShape GetShape(string shape);
}
public class ShapeFactory : AbstractFactory
{
    public override IColor GetColor(string color)
    {
        return null;
    }
    public override IShape GetShape(string shapeType)
    {
        if (shapeType == null)
        {
            return null;
        }
        switch (shapeType)
        {
            case "CIRCLE":
                return new Circle();
            case "RECTANGLE":
                return new Rectangle();
            case "SQUARE":
                return new Square();
        }
        return null;
    }
}
public class ColorFactory : AbstractFactory
{
    public override IColor GetColor(string color)
    {
        if (color == null)
        {
            return null;
        }
        switch (color)
        {
            case "RED":
                return new Red();
            case "GREEN":
                return new Green();
            case "BLUE":
                return new Blue();
        }
        return null;
    }
    public override IShape GetShape(string shape)
    {
        return null;
    }
}

3. UML图:

java抽象工厂举例 抽象工厂 uml_User_02


4. 关键代码:

IFactory productAFactory=new ProductAFactory();
CompanyB conBProductA=productAFactory.CreateProductB();

这里就创建出来了B公司的A产品。

抽象设计模式的缺点:
如果我要增加公司C来生产产品A和产品B,还需要修改,ProductAFactory,ProductBFactoryB,IFactory这三个类,我们可以用简单工厂模式来改进抽象设计模式,我们把这三个类使用swich判断合成一个静态工厂类来改进设计模式:,这里我就不画UML图了,因为上面的抽象模板UML没有写代码,这里直接用大话设计模式里面的数据库抽象工厂模式来优化。
代码如下:

public class AbstractFactorBook : MonoBehaviour
{
    void Start()
    {
        User user = new User();
        Department dept = new Department();
        IUser iu = DataAccess.CreateUser();
        iu.Insert(user);
        iu.GetUser(1);
        IDepartment id = DataAccess.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);
        //
        //User user = new User();
        //Department dept = new Department();
        //IFactorys factory = new AccessFactory();
        //IUser iu = factory.CreateUser();
        //iu.Insert(user);
        //iu.GetUser(1);
        //IDepartment id = factory.CreateDepartment();
        //id.Insert(dept);
        //id.GetDepartment(1);
    }
}

class DataAccess
{
    private static readonly string db = "Sqlserver";
    public static IUser CreateUser()
    {
        IUser result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlserverUser();
                break;
            case "Access":
                result = new AccessUser();
                break;
        }
        return result;
    }
    public static IDepartment CreateDepartment()
    {
        IDepartment result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlserverDepartment();
                break;
            case "Access":
                result = new AccessDepartment();
                break;
        }
        return result;

    }
}

然后我们再使用反射来代替丑陋的swich语句:

public class AbstractFactorBook : MonoBehaviour
{


    void Start()
    {
        User user = new User();
        Department dept = new Department();
        IUser iu = DataReflectionAccess.CreateUser();
        iu.Insert(user);
        iu.GetUser(1);
        IDepartment id = DataReflectionAccess.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);
        //

    }
}
class DataReflectionAccess
{

    private static readonly string db = "Sqlserver";
  //  private static readonly string Namespace = "Null";

    public static IUser CreateUser()
    {
        string AssemblyName = Assembly.GetExecutingAssembly().GetName().Name;//获取程序集名称
        string Namespace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;//获取命名空间名称
        string className = Namespace + "." + db + "User";

        return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);


    }
    public static IDepartment CreateDepartment()
    {
        string AssemblyName = Assembly.GetExecutingAssembly().GetName().Name;//获取程序集名称
        string Namespace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;//获取命名空间名称
        //IDepartment result = null;
        string className = Namespace + "." + db + "Department";

        return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);


    }
}

最后我们只要把
private static readonly string db = “Sqlserver”;这一句在通过配置文件来设置,完美实现了对扩展开放,对修改关闭。
最后做一个总结:
把复杂的东西封装起来。外界通过封装的类来访问。把有需求更改的利用接口,利用继承关系来解决。所以抽象工厂模式就是工厂添加了一个抽象接口。工厂模式是工厂生产一种东西。抽象工厂模式是工厂生产一类东西。