C#設計模式(1)——簡單工廠模式
1.什麽是簡單工廠
現實中的工廠負責生產產品,編程中的簡單工廠顧名思義就是一個生產對象的類,它的主要作用是封裝改變。我們在平時的工作必不可免的和各種數據庫打交道,我們就以一個數據庫服務類為例來分析簡單工廠的作用。代碼如下:
用戶類:
// 用戶類 public class User { public int Id { get; set; } public string Name { get; set; } }
數據庫服務抽象類(DbUserService),主要對用戶進行添加和刪除,類中有兩個抽象方法,AddUser()和RemoveUser():
//數據庫服務抽象類 public abstract class DbUserService { public abstract void AddUser();//添加用戶 public abstract void RemoveUser();//獲取用戶 }
數據庫服務具體類(SqlserverUserService和MysqlUserService),實現類對用戶進行添加和刪除的具體操作:
//Sqlserver中對用戶進行添加和刪除 public class SqlserverUserService:DbUserService {public override void AddUser() { Console.WriteLine("sqlserver 添加一個用戶"); } public override void RemoveUser() { Console.WriteLine("sqlserver 刪除一個用戶"); } } //mysql中對用戶添加和刪除 public class MysqlUserService : DbUserService {public override void AddUser() { Console.WriteLine("Mysql 添加一個用戶"); } public override void RemoveUser() { Console.WriteLine("Mysql 刪除一個用戶"); } }
客戶端代碼:
class Program { static void Main(string[] args) { //我們的軟件中用了很多new來獲取SqlserverUserService的實例 DbUserService userService1 = new SqlserverUserService(); DbUserService userService2 = new SqlserverUserService(); DbUserService userService3 = new SqlserverUserService(); DbUserService userService4 = new SqlserverUserService(); DbUserService userService5 = new SqlserverUserService(); userService1.AddUser(); userService1.RemoveUser(); Console.ReadKey(); } }
運行程序結果如下:
我們可以看到程序運行沒有問題,通過new一個sqlserverUserService服務類實例可以成功地添加和刪除用戶,但是如果我們想把數據庫切換到Mysql怎麽去做呢?最簡單直接的方法就是把 new SqlserverUserService 全部替換成 new MysqlUserService 。如果我們的軟件中new了100個SqlserverUserService實例呢?一個一個地去替換會是一個巨大的工作量,同時通過new的方式來創建SqlserverUserService的實例,會讓DbUserService和客戶端產生強耦合關系,這時候使用簡單工廠就可以幫助我們降低耦合,減少工作量了。添加一個DbUserServiceFactory,這個工廠類專門來創建DbUserService的實例:
//數據庫服務工廠 public class DbUserServiceFactory { public static DbUserService Create(string dbname) { DbUserService dbUserService = null; switch (dbname) { case "sqlserver": dbUserService = new SqlserverUserService(); break; case "mysql": dbUserService = new MysqlUserService(); break; default: break; } return dbUserService; } }
客戶端的代碼就可以改成:
class Program { static void Main(string[] args) { //我們的軟件中用了很多new來獲取SqlserverUserService的實例 DbUserService userService1 = DbUserServiceFactory.Create("sqlserver"); DbUserService userService2 = DbUserServiceFactory.Create("sqlserver"); DbUserService userService3 = DbUserServiceFactory.Create("sqlserver"); DbUserService userService4 = DbUserServiceFactory.Create("sqlserver"); DbUserService userService5 = DbUserServiceFactory.Create("sqlserver"); userService1.AddUser(); userService1.RemoveUser(); Console.ReadKey(); } }
運行程序結果一樣的,這樣做有什麽好處呢?我們看到我們把以前的 new SqlserverUserService() 替換成了 DbUserServiceFactory.Create("sqlserver") ,客戶端和SqlserverUserService的耦合變成了 客戶端<-->DbUserServiceFactory<-->SqlserverUserService 形式,有效降低了客戶端和數據庫服務實現類的耦合。我們還用一個疑問,程序改成這樣的話,如果我們想從SqlServer切換到Mysql就要把DbUserServiceFatroy.Create("sqlserver")中的sqlserver字符串全部替換成mysql字符串,不是還要改100次?任務量沒有降低呀!對於這個問題,我們可以把dbname存放在一個地方,如配置文件中,這樣我們想切換數據庫就直接修改配置文件即可,如下:
配置文件:
<appSettings> <add key="dbname" value="sqlserver"/> </appSettings>
工廠類修改為:
//數據庫服務工廠 public class DbUserServiceFactory { private static readonly string dbname = ConfigurationManager.AppSettings["dbname"]; public static DbUserService Create() { DbUserService dbUserService = null; switch (dbname) { case "sqlserver": dbUserService = new SqlserverUserService(); break; case "mysql": dbUserService = new MysqlUserService(); break; default: break; } return dbUserService; } }
客戶端代碼如下:
class Program { static void Main(string[] args) { DbUserService userService1 = DbUserServiceFactory.Create(); DbUserService userService2 = DbUserServiceFactory.Create(); DbUserService userService3 = DbUserServiceFactory.Create(); DbUserService userService4 = DbUserServiceFactory.Create(); DbUserService userService5 = DbUserServiceFactory.Create(); userService1.AddUser(); userService1.RemoveUser(); Console.ReadKey(); } }
現在我們想把數據庫服務切換到mysql,只需要將配置文件中的sqlserver改成mysql即可,修改配置文件後運行結果如下:
大功告成!這時有一個問題,如果我們想添加一個mongodb服務怎麽辦呢?除了添加一個MongodbUserService類,還要在UserServiceFactory類中添加一段case 代碼。按照開閉原則,添加一個實現類沒什麽問題,開閉原則中對添加開發;但是修改簡單工廠類就違背了對修改閉合的原則了。後邊的工廠模式就是專門用來解決這個問題的。
2.小結
上邊例子的類圖:
簡單工廠的優點:
1.簡單工廠可以有效地降低客戶端和具體對象的耦合,將new具體對象的任務交給了一個簡單工廠類
2可以有效的進行代碼復用,如客戶端A和客戶端B都需要一個具體對象,客戶端A和客戶端B都可以通過同一個簡單工廠來獲取具體類型的實例
簡單工廠的缺點:
一定程度上違背了開閉原則,在新增產品時需要修改簡單工廠類
C#設計模式(1)——簡單工廠模式