微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

第六课 抽象工厂模式

第六课 抽象工厂模式

 

       抽象工厂模式其实和工厂方法模式思路一样,可以说是工厂方法模式的一个特例,用于控制一个系列的产品的不同版本。简单举个例子(可能不适用于.net)我现在有几个界面UI控件产品,Button,Label,TextBox。大家应该知道,windowsMac系统底层对UI的实现不同,所以创建控件的方式可能不同。这样我可能出2套产品,一套是为Windows实现的,另一套是基于Mac实现的。这样我为了方便的获得两套产品,就需要用抽象工厂模式。换句话说,抽象工厂在应用的时候,需要判断产品的横向和纵向。假设横向是一个系列的产品,纵向是不同的版本实现的话,就有类似下面这样的一个矩阵。

 

ButtonForWin  LabelForWin  TextBoxForWin

ButtonForMac  LabelForMac  TextBoxForMac

ButtonForLinux   LabelForLinux   TextBoxForLinux

 

其实就是3个产品,Button Label TextBox ,但是针对3个操作系统实现了3个版本而已。

这样大家有点印象了吧,下面开始看代码Java

首先系列产品的抽象

1.        public interface Button

2.        {

3.            ...

4.        }

5.       

 

6.        public interface Label

7.        {

8.            ...

9.        }

这里我懒的打TextBox了,就用俩来看吧。

 

然后Windows实现:

1.        public class WinButton implements Button

2.        {

3.            ...

4.        }

5.       

 

6.        public class WinLabel implements Label

7.        {

8.            ...

9.        }

 

再看Mac实现:

1.        public class MacButton implements Button

2.        {

3.            ...

4.        }

5.       

 

6.        public class MacLabel implements Label

7.        {

8.            ...

9.        }

 

WindowsMac的实现UI方式肯定不同,这里不描述了。

 

然后来看工厂:

1.       

 

2.        public abstract class UIProducer

3.        {

4.            public abstract Button createButton();

5.       

 

6.            public abstract Label createLabel();

7.       

 

8.            public static UIProducer getInstance(String which)

9.            {

10.         if (which.equalsIgnoreCase("Win"))

11.             {

12.                 return WinProducer.getInstance();

13.             }

14.             else if (which.equalsIgnoreCase("Mac"))

15.             {

16.                 return MacProducer.getInstance();

17.             }

18.             return null;

19.         }

20.     }

21.    

 

22.     public class WinProducer extends UIProducer

23.     {

24.         private static WinProducer producer = new WinProducer ();

25.    

 

26.         private WinProducer()

27.         {

28.         }

29.    

 

30.         public Button createButton()

31.         {

32.             return new WinButton();

33.         }

34.    

 

35.         public Label createLabel()

36.         {

37.             return new WinLabel();

38.         }

39.    

 

40.         public static WinProducer getInstance()

41.         {

42.             return producer;

43.         }

44.    

 

45.    

 

46.     }

47.    

 

48.     public class MacProducer extends ComputerProducer

49.     {

50.         private static MacProducer producer = new MacProducer();

51.    

 

52.         private MacProducer() {

53.         }

54.    

 

55.         public Button createButton()

56.         {

57.             return new MacButton();

58.         }

59.    

 

60.         public Label createram()

61.         {

62.             return new MacLabel();

63.         }

64.    

 

65.         public static MacProducer getInstance()

66.         {

67.             return producer;

68.         }

69.    

 

70.     }

 

这里使用了类似工厂方法模式,使用了一个抽象工厂基类。但是实现方式不同,请仔细观察。这里没有用接口,使用了抽象类,同事没有定义抽象生产方法,采用了简单工厂模式的方式返回实现的工厂对象。这里如果我系统是针对Windows开发的,那么我可以使用:

1.        UIProducer winUI = UIProducer.getInstance("Win");

来获得生产Windows下产品的工厂,反之使用:

2.        UIProducer winUI = UIProducer.getInstance("Mac");

来获得生产Mac系统下产品的工厂。

 

现在大家能够体会到抽象工厂的用法了吧。

在你判断一套产品有可能要为不同的需求做几套不同的实现的产品的时候,其实简单说就是一套东西要做几个版本的实现的时候,就可以考虑抽象工厂。

再来看一个《大话设计模式》中的例子,这个是针对不同种类数据库实现的例子。

C#代码

1.        using System;

2.        using System.Collections.Generic;

3.        using System.Text;

4.        using System.Reflection;

5.        using System.Configuration;

6.       

 

7.        namespace 抽象工厂模式

8.        {

9.            class Program

10.         {

11.             static void  Main (string[] args)

12.             {

13.                 User user = new User();

14.                 Department dept = new Department();

15.    

 

16.                 IUser iu = DataAccess.createuser();

17.    

 

18.                 iu.Insert(user);

19.                 iu.GetUser(1);

20.    

 

21.                 IDepartment id = DataAccess.CreateDepartment();

22.                 id.Insert(dept);

23.                 id.GetDepartment(1);

24.    

 

25.                 Console.Read();

26.             }

27.         }

28.    

 

29.         class User

30.         {

31.             private int _id;

32.             public int ID

33.             {

34.                 get { return _id; }

35.                 set { _id = value; }

36.             }

37.    

 

38.             private string _name;

39.             public string Name

40.             {

41.                 get { return _name; }

42.                 set { _name = value; }

43.             }

44.         }

45.    

 

46.         class Department

47.         {

48.             private int _id;

49.             public int ID

50.             {

51.                 get { return _id; }

52.                 set { _id = value; }

53.             }

54.    

 

55.             private string _deptName;

56.             public string DeptName

57.             {

58.                 get { return _deptName; }

59.                 set { _deptName = value; }

60.             }

61.         }

62.    

 

63.         interface IUser

64.         {

65.             void Insert(User user);

66.    

 

67.             User GetUser(int id);

68.         }

69.    

 

70.         class sqlserverUser : IUser

71.         {

72.             public void Insert(User user)

73.             {

74.                 Console.WriteLine("sqlserver中给User增加一条记录");

75.             }

76.    

 

77.             public User GetUser(int id)

78.             {

79.                 Console.WriteLine("sqlserver中根据ID得到User表一条记录");

80.                 return null;

81.             }

82.         }

83.    

 

84.         class AccessUser : IUser

85.         {

86.             public void Insert(User user)

87.             {

88.                 Console.WriteLine("Access中给User增加一条记录");

89.             }

90.    

 

91.             public User GetUser(int id)

92.             {

93.                 Console.WriteLine("Access中根据ID得到User表一条记录");

94.                 return null;

95.             }

96.         }

97.    

 

98.         interface IDepartment

99.         {

100.          void Insert(Department department);

101. 

 

102.          Department GetDepartment(int id);

103.      }

104. 

 

105.      class sqlserverDepartment : IDepartment

106.      {

107.          public void Insert(Department department)

108.          {

109.              Console.WriteLine("sqlserver中给Department增加一条记录");

110.          }

111. 

 

112.          public Department GetDepartment(int id)

113.          {

114.              Console.WriteLine("sqlserver中根据ID得到Department表一条记录");

115.              return null;

116.          }

117.      }

118. 

 

119.      class AccessDepartment : IDepartment

120.      {

121.          public void Insert(Department department)

122.          {

123.              Console.WriteLine("Access中给Department增加一条记录");

124.          }

125. 

 

126.          public Department GetDepartment(int id)

127.          {

128.              Console.WriteLine("Access中根据ID得到Department表一条记录");

129.              return null;

130.          }

131.      }

132. 

 

133.      class DataAccess

134.      {

135.          private static readonly string AssemblyName = "抽象工厂模式";

136.          private static readonly string db = ConfigurationManager.AppSettings["DB"];

137.          

138.          public static IUser createuser()

139.          {

140.              string className = AssemblyName + "." + db + "User";

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

142.          }

143. 

 

144.          public static IDepartment CreateDepartment()

145.          {

146.              string className = AssemblyName + "." + db + "Department";

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

148.          }

149.      }

150. 

 

151.  }

 

这里一共出现了2个产品对象,用户和部门。

针对两个产品做了2个版本实现 Access sqlServer

这样的好处是什么呢,如果我现在要把系统安装在一个装有sqlServer数据库的机器上的时候,我就可以直接调用sqlServer工厂类,给我生产sql版的产品来用,如果装在一个只有Access数据库的机器上时,我可以直接用Access工厂类,生产Access产品来使用。不用修改代码。你可能会问,为什么不用修改代码调用的时候需要给参数啊。这里你看看

DataAccess这个类的实现方法。这里应用了一个动态加载类的方式

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

这个方式可以通过一串文本(指明类的目录及类名)来生成类对象。当然生成的是Object对象,但是可以通过强制转换成基类来调用吗。你又要问了,字符串也是后台写得啊,还是需要改代码啊。我回答,笨啊你,谁说字符串非要写在后台,我写到配置文件里去不行吗?你看:

private static readonly string db = ConfigurationManager.AppSettings["DB"];

这句是干什么用的啊。这不是读配置文件里的节点吗。

 

下面给出配置文件

1.        <?xml version="1.0" encoding="utf-8" ?>

2.        <configuration>

3.            <appSettings>

4.                <add key="DB" value="sqlserver"/>

5.            </appSettings>

6.        </configuration>

 

看到了没这里配置的是sqlserver 所以后台肯定是生成sqlServer工厂了。

这样我的程序如果改用Access数据库的话,我只要修改配置文件即可。完全避免的代码修改。怎么样,有用吧。

 

好了,今天的课就到这里,明天讲什么呢,我回去想想吧。同志们期待吧。

 

作者:王文斌

转载请注明出处。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐