1. 程式人生 > >C#設計模式(1)——簡單工廠模式

C#設計模式(1)——簡單工廠模式

void 例子 代碼復用 操作 inf 這樣的 man ger troy

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)——簡單工廠模式