抽象工厂模式(Abstract factory Pattern)

    有个项目原来是依赖于access数据库,现在要用sqlserver,怎么更改呢(解耦)?

    IUser接口,用于客户端访问,解除与具体数据库访问的耦合。

    Sqlserver类,用于访问SQL Server的User。

    1. {
    2. public void Insert(User user)
    3. {
    4. Console.WriteLine("在SQL Server中给User表增加一条记录");
    5. }
    6. public User GetUser(int id)
    7. {
    8. Console.WriteLine("在SQL Server中给User表获取一条记录");
    9. return null;
    10. }
    11. }

    AccessUser类,用于访问Access的User。

    1. class AccessUser : IUser
    2. {
    3. public void Insert(User user)
    4. {
    5. Console.WriteLine("在access中给User表增加一条记录");
    6. }
    7. public User GetUser(int id)
    8. {
    9. Console.WriteLine("在access中给User表获取一条记录");
    10. return null;
    11. }
    12. }

    IFactory接口,定义一个创建访问User表对象的抽象的工厂接口。

    1. interface Ifactory
    2. {
    3. IUser CreateUser();
    4. }

    sqlServerFactory类,实现IFactory接口,实例化SqlserverUser。

    1. class sqlServerFactory: IFactory
    2. {
    3. public IUser CreateUser()
    4. {
    5. return new SqlserverUser();
    6. }
    7. }

    AccessFactory类,实现IFactory接口,实例化AccessUser.

    1. class AccessFactory: IFactory
    2. {
    3. public IUser CreateUser()
    4. {
    5. return new AccessUser();
    6. }
    7. }

    客户端代码

    1. static void main(string[] args)
    2. {
    3. User user = new User();
    4. IFactory factory = new SqlServerFactory();
    5. IUser iu = factory.CreateUser();
    6. iu.Insert(user);
    7. iu.GetUser(1);
    8. Console.Read();
    9. }

    但是数据里面不可能只有一个User表,比如说增加部门表,此时怎么办呢。

    SqlserverDepartment类,用于访问SQL Server的Department。

    1. class SqlserverDepartment : IDepartment
    2. {
    3. public void Insert(Department department)
    4. {
    5. Console.WriteLine("在SQL Server中给Department表增加一条记录");
    6. }
    7. public Department GetDepartment(int id)
    8. {
    9. Console.WriteLine("在SQL Server中给Department表获取一条记录");
    10. return null;
    11. }
    12. }

    AccessDepartment类,用于访问Access的Department。

    1. class AccessDepartment : IDepartment
    2. {
    3. public void Insert(Department department)
    4. Console.WriteLine("在Access中给Department表增加一条记录");
    5. }
    6. public Department GetDepartment(int id)
    7. {
    8. return null;
    9. }
    10. }

    1. interface IUser
    2. {
    3. void Insert(User user);
    4. User GetUser(int id);
    5. }

    Sqlserver类,用于访问SQL Server的User。

    1. class SqlserverUser : IUser
    2. {
    3. public void Insert(User user)
    4. {
    5. Console.WriteLine("在SQL Server中给User表增加一条记录");
    6. }
    7. public User GetUser(int id)
    8. {
    9. Console.WriteLine("在SQL Server中给User表获取一条记录");
    10. return null;
    11. }
    12. }

    AccessUser类,用于访问Access的User。

    1. class AccessUser : IUser
    2. {
    3. public void Insert(User user)
    4. {
    5. Console.WriteLine("在access中给User表增加一条记录");
    6. }
    7. public User GetUser(int id)
    8. {
    9. Console.WriteLine("在access中给User表获取一条记录");
    10. return null;
    11. }
    12. }

    IFactory接口,定义一个创建访问User表对象的抽象的工厂接口。

    1. interface Ifactory
    2. {
    3. IUser CreateUser();
    4. IDepartment CreateDepartment();
    5. }

    sqlServerFactory类,实现IFactory接口,实例化SqlserverUser。

    AccessFactory类,实现IFactory接口,实例化AccessUser.

    1. class AccessFactory: IFactory
    2. {
    3. public IUser CreateUser()
    4. {
    5. return new AccessUser();
    6. }
    7. public IDepartment CreateDepartment()
    8. {
    9. return new AccessDepartment();
    10. }
    11. }

    客户端代码

    1. static void main(string[] args)
    2. {
    3. User user = new User();
    4. IFactory factory = new SqlServerFactory();
    5. IUser iu = factory.CreateUser();
    6. iu.Insert(user);
    7. iu.GetUser(1);
    8. Console.Read();
    9. }

    抽象工厂模式:提供一个创建一系列相关或者相互依赖的对象的接口,而无需指定它们具体的类。

    1. class DataAccess
    2. {
    3. private static readonly string db = "Sqlserver";
    4. // private static readonly string db = "access";
    5. public static IUser CreateUser()
    6. {
    7. IUser result = null;
    8. switch (db)
    9. {
    10. case:"Sqlserver":
    11. break;
    12. case:"Acesss":
    13. result = new AcesssUser();
    14. break;
    15. }
    16. return result;
    17. }
    18. publci static IDepartment CreateDepartment()
    19. {
    20. IDepartment result = null;
    21. switch (db)
    22. {
    23. case:"Sqlserver":
    24. result = new SqlserverDepartment();
    25. break;
    26. case:"Acesss":
    27. result = new AcesssDepartment();
    28. break;
    29. }
    30. return result;
    31. }
    32. }
    1. static void Main(string[] args)
    2. {
    3. User user = new User();
    4. Department dept = new Department();
    5. IUser iu = DataAccess.createUser();
    6. iu.Insert(user);
    7. iu.GetUser(1);
    8. IDepartment id = DataAccess.createDepartment();
    9. id.Inert(dept);
    10. id.GetDepartment(1);
    11. Console.Read();
    12. }

    利用反射或者配置文件都可以减少在所有简单工厂的switch和if,解除分支判断带来的耦合。

    “工厂”是创建产品(对象)的地方,其目的是将产品的创建与产品的使用分离。抽象工厂模式的目的,是将若干抽象产品的接口与不同主题产品的具体实现分离开。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的客户端代码。

    使用抽象工厂模式,能够在具体工厂变化的时候,不用修改使用工厂的客户端代码,甚至是在运行时。然而,使用这种模式或者相似的设计模式,可能给编写代码带来不必要的复杂性和额外的工作。正确使用设计模式能够抵消这样的“额外工作”。

    Class Clusters(类簇)是抽象工厂模式在iOS下的一种实现,众多常用类,如NSString,NSArray,NSDictionary,NSNumber都运作在这一模式下,它是接口简单性和扩展性的权衡体现,在我们完全不知情的情况下,偷偷隐藏了很多具体的实现类,只暴露出简单的接口。

    虽然官方文档中拿NSNumber说事儿,但Foundation并没有像图中描述的那样为每个number都弄一个子类,于是研究下NSArray类簇的实现方式。

    熟悉这个模式的同学很可能看过下面的测试代码,将原有的alloc+init拆开写:

    1. id obj1 = [NSArray alloc]; // __NSPlacehodlerArray *
    2. id obj2 = [NSMutableArray alloc]; // __NSPlacehodlerArray *
    3. id obj3 = [obj1 init]; // __NSArrayI *
    4. id obj4 = [obj2 init]; // __NSArrayM *

    发现+ alloc后并非生成了我们期望的类实例,而是一个NSPlacehodlerArray的中间对象,后面的- init或- initWithXXXXX消息都是发送给这个中间对象,再由它做工厂,生成真的对象。这里的NSArrayI和__NSArrayM分别对应Immutable和Mutable(后面的I和M的意思)

    于是顺着思路猜实现,__NSPlacehodlerArray必定用某种方式存储了它是由谁alloc出来的这个信息,才能在init的时候知道要创建的是可变数组还是不可变数组

    经过研究发现,Foundation用了一个很贱的比较静态实例地址方式来实现,伪代码如下:

    1. static __NSPlacehodlerArray *GetPlaceholderForNSArray() {
    2. static __NSPlacehodlerArray *instanceForNSArray;
    3. if (!instanceForNSArray) {
    4. instanceForNSArray = [[__NSPlacehodlerArray alloc] init];
    5. }
    6. return instanceForNSArray;
    7. }
    8. static __NSPlacehodlerArray *GetPlaceholderForNSMutableArray() {
    9. static __NSPlacehodlerArray *instanceForNSMutableArray;
    10. if (!instanceForNSMutableArray) {
    11. instanceForNSMutableArray = [[__NSPlacehodlerArray alloc] init];
    12. }
    13. return instanceForNSMutableArray;
    14. }
    15. // NSArray实现
    16. + (id)alloc {
    17. if (self == [NSArray class]) {
    18. return GetPlaceholderForNSArray()
    19. }
    20. }
    21. // NSMutableArray实现
    22. + (id)alloc {
    23. if (self == [NSMutableArray class]) {
    24. return GetPlaceholderForNSMutableArray()
    25. }
    26. }
    27. // __NSPlacehodlerArray实现
    28. - (id)init {
    29. if (self == GetPlaceholderForNSArray()) {
    30. self = [[__NSArrayI alloc] init];
    31. }
    32. else if (self == GetPlaceholderForNSMutableArray()) {
    33. self = [[__NSArrayM alloc] init];
    34. }
    35. }