java設計模式----factory

  工廠模式一共分爲三種,分別是:簡單工廠模式,工廠方法模式和抽象工廠模式。

 

    先來說說簡單工廠模式,簡單工廠模式一般不在實際中是用,因爲它的擴展性不好,這裏的擴展性,是指我們可以添加新的類,而不是去更改現有的類,這樣做的好處顯而易見,如果爲了一個新需求去更改原有類的代碼,那麼就有可能引入新的bug,如果是新加一個類,這就可以非常有效地降低引入新bug的風險,因此,擴展性是非常重要的。下面是一個簡單工廠模式的例子:

 

   

  1. public interface Fruit{  
  2.       
  3. }  
  4. public class Apple implements Fruit{  
  5. }  
  6. public class Grape implements Fruit{  
  7. }  
  8. public class Strawberry implements Fruit{  
  9. }  
  10. public class FruitGardener  
  11. {  
  12.     public static Fruit factory(String whichFruit)  
  13.     {  
  14.         if (which.equalsIgnoreCase("apple"))  
  15.         {  
  16.             return new Apple();  
  17.         }  
  18.         else if (which.equalsIgnoreCase("strawberry"))  
  19.         {  
  20.             return new Strawberry();  
  21.         }  
  22.         else if (which.equalsIgnoreCase("grape"))  
  23.         {  
  24.             return new Grape();  
  25.         }  
  26.         else  
  27.         {  
  28.             return new null;  
  29.         }  
  30.     }  
  31. }  

 

    上面的代碼很容易看懂,想要得到一個Apple,用Apple apple = FruitGardener.factory("apple");這句話就行了。這樣看來,上面的代碼已經實現了工廠模式,事實也的確如此,但是問題就在於先前所提到的擴展性,當我們想要這個果園能生產香蕉的時候,必須做下面兩件事情,第一,寫一個Banana類,它實現了接口Fruit,然後再更改FruitGardener,讓其能夠生產Banana,如下:

 

   

  1. public class Banana implements Fruit{  
  2. }  
  3. public class FruitGardener  
  4. {  
  5.     public static Fruit factory(String whichFruit)  
  6.     {  
  7.         if (which.equalsIgnoreCase("apple"))  
  8.         {  
  9.             return new Apple();  
  10.         }  
  11.         else if (which.equalsIgnoreCase("strawberry"))  
  12.         {  
  13.             return new Strawberry();  
  14.         }  
  15.         else if (which.equalsIgnoreCase("grape"))  
  16.         {  
  17.             return new Grape();  
  18.         }  
  19.         else if (which.equalsIgnoreCase("banana"))  
  20.         {  
  21.             return new Banana();  
  22.         }  
  23.         else  
  24.         {  
  25.             return new null;  
  26.         }  
  27.           
  28.     }  
  29. }  

 

    這樣就違背了我們先前說的只能新加類,不能修改現有類的原則,因此,簡單工廠模式只能做一個教學演示而已。

 

    下面是第二個,叫工廠方法模式,這個方法有效地解決了簡單工廠模式擴展性差的問題,想要進行擴展,只需要新加類就行,不需要更改原油類,下面是一個例子:

   

  1. public interface Mobile {   
  2. }  
  3. public class Motorola implements Mobile {    
  4. }  
  5. public class Nokia implements Mobile {    
  6. }  
  7. public interface MobileFactory {    
  8.     public Mobile produceMobile();    
  9. }   
  10. public class NokiaFactory implements MobileFactory {   
  11.     @Override    
  12.     public Mobile produceMobile() {    
  13.         return new Nokia();    
  14.     }    
  15. }    
  16. public class MotorolaFactory implements MobileFactory {   
  17.     @Override    
  18.     public Mobile produceMobile() {    
  19.         return new Motorola();    
  20.     }    
  21. }   
  22. public class Client {    
  23.     public static void main(String[] args){    
  24.         MobileFactory mf;    
  25.         Mobile m;    
  26.         mf = new MotorolaFactory();    
  27.         m = mf.produceMobile();      
  28.         //這時,m是Motorola的手機   
  29.         mf = new NokiaFactory();    
  30.         m = mf.produceMobile();   
  31.         //這時,m是Nokia的手機   
  32.     }    
  33. }   

 

    如果想要生產HTC的手機,只需要新加一個HTC類,實現Mobile接口,再新加一個HTCFactory,實現MobileFactory接口就行了,新加的代碼如下:

   

  1. public class HTC implements Mobile {    
  2. }  
  3. public class HTCFactory implements MobileFactory {   
  4.     @Override    
  5.     public Mobile produceMobile() {    
  6.         return new HTC();    
  7.     }    
  8. }  

 

    這樣就實現了新加一個這個工廠產的產品,但是不會更改原有類的要求,但是,這還會有問題。在工廠方法模式中,到底生產什麼,是寫進了代碼裏(我們俗稱硬代碼),假如客戶這次想要Nokia,下次又想要Motorola了怎麼辦,總不可能他提一次需求我們就改一次代碼吧,這樣顯然是不行的,因此,下面又有了抽象工廠模式。先是一個例子:

 

   

  1. interface Dao {   
  2. }    
  3.    
  4. class OracleDao implements Dao {   
  5. }    
  6.   
  7. class MySqlDao implements Dao {  
  8. }    
  9.   
  10. abstract class DaoFactory {    
  11.     abstract Dao getDao();   
  12.     public static DaoFactory getInstance(String classname) {    
  13.         DaoFactory dao = null;    
  14.         try {    
  15.             dao = (DaoFactory) Class.forName(classname).newInstance();    
  16.         } catch (Exception e) {    
  17.             e.printStackTrace();    
  18.         }    
  19.         return dao;    
  20.     }    
  21. }    
  22.   
  23. class OracleFactory extends DaoFactory {    
  24.     @Override  
  25.     Dao getDao() {  
  26.         // TODO Auto-generated method stub   
  27.         return new OracleDao();    
  28.     }     
  29. }    
  30.   
  31. class MysqlFactory extends DaoFactory {    
  32.     @Override  
  33.     public Dao getDao() {  
  34.         // TODO Auto-generated method stub   
  35.         return new MySqlDao();    
  36.     }    
  37. }    
  38. class Config {    
  39.     static final String FACTORYNAME = "OracleFactory";   
  40. }   
  41. public class Test {    
  42.     public static void main(String[] args) {    
  43.         Dao dao = null;  
  44.         dao = DaoFactory.getInstance(Config.FACTORYNAME).getDao();  
  45.         System.out.println(dao.getClass().getName());  
  46.         //打印的結果是OracleDao   
  47.     }   
  48. }   

 

    上面的代碼中,想要生產什麼,是寫在配置文件裏的,Config這個類實際上可以寫成一個properties文件,用戶想要生產什麼,按照要求改這個文件就可以了,不需要改代碼。再回頭看看這個抽象工廠模式滿不滿足可擴展性,如果想要生產SqlServer的數據庫訪問對象(DAO,Data Access Object),需要新加一個SqlServerDao類來實現DAO接口,再新增一個SqlServerFactory實現DaoFactory,另外,需要告訴客戶現在的系統已經能夠生產SqlServer數據訪問對象了,你只需要在配置文件里加上類似static final String MYSQL = "org.abc.SqlServerFactory"; 的話(按照配置文件的格式來寫)就行了。

 

    上面就介紹完了工廠模式,下期預告,Builder模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章