Java設計模式二

今天談的是工廠模式,該模式用於封裝和對對象的創建,萬物皆對象,那麼萬物又是產品類,如一個水果廠生產三種水果罐頭,我們就可以將這三種水果作為產品類,再定義一個介面用來設定對水果罐頭的生成方法,在工廠類中定義一個方法可以根據我們提供給工廠的不同參數,來生成不同的產品。這樣我們就可以方便後續的擴展,例如工廠又新生產另一種水果罐頭,那麼我們只需要添加相應的水果類,傳入工廠相應的製造方法即可。下面我們通過具體的程式碼來理解工廠模式的實現。

標準的工廠類設計

工廠類的定義是:定義一個用於創建對象的介面,讓子類決定實例化哪個類,工廠方法使得一個類的實例化延遲到子類。我們定義一個水果類(抽象),讓蘋果,桔子類繼承水果類。定義一個工廠(抽象),使用泛型的抽象方法,再定義一個或者多個具體的工廠繼承該抽象工廠的抽象方法。生產中當調用工廠時傳入想要生產的水果類(具體)即可。

package com.factor;  /**   * 抽象水果類   */  public abstract class Fruit {      public void getClassname(){          System.out.println("我屬於水果");      }      public abstract void getname();    }
package com.factor;  /**   *   * @author Administrator   * 蘋果   */  public class Apple extends Fruit{        public void getname() {          // TODO Auto-generated method stub          System.out.println("我是一個蘋果");      }      }
package com.factor;  /**   *   * @author Administrator   * 桔子   */  public class Orange extends Fruit{        public void getname() {          // TODO Auto-generated method stub          System.out.println("我是一個桔子");        }    }
/**   *   * @author Administrator   * 抽象工廠   */  public abstract class AbstractFactory {      public abstract <T extends Fruit> T createFriut(Class<T> c);        }
/**   *   * @author Administrator   * 水果工廠   */  public class FruitFactory extends AbstractFactory {        @Override      public <T extends Fruit> T createFriut(Class<T> c) {          // TODO Auto-generated method stub          System.out.println("開始製作");          Fruit fruit=null;          try {              fruit = (Fruit)Class.forName(c.getName()).newInstance();            } catch (Exception e) {              // TODO Auto-generated catch block              e.printStackTrace();          }          return (T)fruit;        }    }

場景類:

public class Click {        /**       * @param args       */      public static void main(String[] args) {          // TODO Auto-generated method stub            AbstractFactory factory = new FruitFactory();          Fruit apple = factory.createFriut(Apple.class);          apple.getClassname();          apple.getname();        }    }

運行結果

工廠方法模式擁有良好的封裝性,程式碼結構清晰,另外對對象的創建有約束的作用如上面程式碼中使用界定限制工廠只能生產水果),其次工廠模式的擴展性也很優秀,如需要增加產品的生產,只添加相應的產品類,適當的修改或者增加一個工廠類即可。我們從工廠方法中也能看到迪米特法則的運用,也就是高層模組只需要知道產品的抽象類,其它的類「不關心」。也可以看出一個產品只依賴產品的抽象這也是符合依賴倒置的。

工廠模式擴展

1.縮小為簡單工廠模式
如果我們只需要一個工廠生產水果,那麼我們可以把工廠抽象類中的方法放到具體工廠類中即可。

/**   *   * @author Administrator   * 水果工廠   */  public class FruitFactory   {        public static <T extends Fruit> T createFriut(Class<T> c) {          // TODO Auto-generated method stub          System.out.println("開始製作");          Fruit fruit=null;          try {              fruit = (Fruit)Class.forName(c.getName()).newInstance();            } catch (Exception e) {              // TODO Auto-generated catch block              e.printStackTrace();          }          return (T)fruit;        }    }

這使得我們的類變得簡單,而且調用也簡單了,所以稱為簡單工廠模式也叫做靜態工廠模式。這樣做也存在不符合開閉原則的缺點,不利於擴展。
2.多工廠模式
我們可以使用多個工廠來生產產品,比如有蘋果工廠,有桔子工廠等。

/**   *   * @author Administrator   * 多工廠中的抽象工廠  區別: 不適用泛型 直接生成一個產品大類   */  public abstract class MaxFaxtory {      public abstract Fruit create();        }

具體的工廠類:

/**   *   * @author Administrator   * 多工廠模式   */  public class AppleFactory extends MaxFaxtory {        @Override      public Fruit create() {          // TODO Auto-generated method stub          return new Apple();      }
/**   *   * @author Administrator   * 所工廠模式  桔子工廠   */  public class OracleFactory extends MaxFaxtory{        @Override      public Fruit create() {          // TODO Auto-generated method stub          return new Orange();      }      }

這樣做使得各個工廠之間職責清晰,結構簡單,但也是不利於擴展。我們可以使用一個協調類避免調用者與各個子工廠交流,協調類的作用是封裝工廠類,對高層模組提供統一的訪問介面。
3.替代單例模式

/**   *   * @author Administrator   * 單例類   */  public class Singleton {      //不允許new      private Singleton(){        }      public void doSomething(){        }    }
import java.lang.reflect.Constructor;  import java.lang.reflect.InvocationTargetException;    public class SingletonFactory {      private static Singleton singleton;      static{          try {              Class c1=Class.forName(Singleton.class.getName());              Constructor constructor=c1.getDeclaredConstructor();              constructor.setAccessible(true);              singleton = (Singleton)constructor.newInstance();          } catch (Exception e) {              // TODO Auto-generated catch block              e.printStackTrace();          }          }    }

SingletonFactory通過反射的方法創建一個單例對象。

4.延遲初始化
一個對象被消費完畢後,並不立即釋放,而是保持初始狀態,等待再次被調用。

  /**   *   * @author Administrator   * 延遲載入的工廠類   */  public class ProductFactory {      private static final Map<String,Fruit> prMap = new HashMap();      public static synchronized Fruit createFruit(String type) throws Exception{          Fruit fruit = null;          if(prMap.containsKey(type)){              fruit = prMap.get(type);            }else{              if(type.equals("apple")){                  fruit = new Apple();              }else{                  fruit = new Orange();              }          }          return fruit;      }    }

延遲載入的框架易於擴展,可以通過判斷Map中已有的對象數量來實現。通過延遲載入也降低了對象生成與銷毀帶來的問題。