概念以及背景
簡單工廠模式(Simple Factory Pattern):定義一個工廠類,它能夠根據參數的不一樣返回不一樣類的實例,被建立的實例一般都具備共同的父類。
由於在簡單工廠模式中用於建立實例的方法是靜態(static)方法,所以簡單工廠模式又被稱爲靜態工廠方法(Static Factory Method)模式,它屬於類建立型模式。
工廠模式是最經常使用的一類建立型設計模式,一般咱們所說的工廠模式是指工廠方法模式而簡單工廠模式並不屬於GoF 23個經典設計模式,但一般將它做爲學習其餘工廠模式的基礎。
簡單地說就是須要什麼對象,傳入給定格式的參數,就能夠獲取所需對象,而調用方無需知道其中建立對象的細節,在建立對象那一方也有本身的實現細節,代碼結構清晰、解耦。
源碼地址:https://github.com/fiuty/stud...
裏面用三種不一樣的方式應用了簡單工廠模式,有用到Java8 Lambda 方式重構簡單工廠模式,也有一個我實際開發中應用到的方式。git
UML類圖以下,有一個抽象金融產品類AbstractFinanceProduct,有三個子類,貸款(LoanFinanceProduct)、股票(StockFinanceProduct)和債券(BondFinanceProduct)都是抽象金融產品類(AbstractFinanceProduct)的子類。
工廠類是SimpleFactory,負責建對象,根據傳入的參數,返回須要的對象。
github
/** * 抽象金融產品類 */ public abstract class AbstractFinanceProduct { /** * 全部產品類的公共業務方法 */ public void methodSame() { String className = this.getClass().getName(); //公共方法的實現 System.out.println("抽象類公共方法,該類是:" + className); } /** * 聲明抽象業務方法 */ public abstract void disPlayProduct(); }
產品名稱枚舉,用於工廠類建立對象方法的參數,用枚舉的話比用常量好,常量的話方法參數調用方可能會給超出產品範圍的常量,而用枚舉的話產品枚舉類範圍都是明確的,也不用擔憂寫錯,如把股票Stock寫成Stick等錯誤寫法。設計模式
/** * 產品名稱枚舉 */ public enum ProductEnum { /** * 產品類別 */ Bond("Bond"), Loan("Loan"), Stock("Stock"); String name; ProductEnum(String name) { this.name = name; } }
/** * 簡單工廠類 */ class SimpleFactory { static AbstractFinanceProduct creatProduct(ProductEnum productEnum) { switch (productEnum) { case Bond : return new BondFinanceProduct(); case Loan : return new LoanFinanceProduct(); case Stock : return new StockFinanceProduct(); default: throw new RuntimeException("No such product" + productEnum.name()); } } }
工廠類的調用方,只需傳入某個產品的類別,便可返回該產品對象。ide
public class SimpleFactoryPattern { public static void main(String[] args) { AbstractFinanceProduct stockProduct = SimpleFactory.creatProduct(ProductEnum.Stock); AbstractFinanceProduct bondProduct = SimpleFactory.creatProduct(ProductEnum.Bond); stockProduct.methodSame(); stockProduct.disPlayProduct(); bondProduct.disPlayProduct(); } }
跟步驟一的UML類圖同樣,以下:
函數
用lambda的方式實現簡單工廠模式,lambda給咱們提供了一些經常使用的函數式接口能夠用,簡單工廠模式須要建對象和返回對象,故可用Supplier<T>函數式接口,至於建立所需對象的入參,接着下面看。學習
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
這裏把所需建立對象的入參作成一個Map的key鍵,而Map的value是一個函數式接口,在設值的時候用lambda實現該value的函數式接口,這裏巧妙地用了lambda的方法引用ClassName::new,實現函數式接口Supplier<T>的get()接口方法。this
/** * 用lambda的方式實現簡單工廠模式 */ class SimpleFactoryLambda { /** * Map的value是一個函數式接口,裏面的接口待實現 */ private final static Map<ProductEnum, Supplier<AbstractFinanceProduct>> PRODEUC_MAP = new HashMap<>(); static { //這裏put進去的value就是函數式接口的一個實現,lambda表達式的方法引用 PRODEUC_MAP.put(ProductEnum.Bond, BondFinanceProduct::new); PRODEUC_MAP.put(ProductEnum.Stock, StockFinanceProduct::new); PRODEUC_MAP.put(ProductEnum.Loan, LoanFinanceProduct::new); } static AbstractFinanceProduct creatProduct(ProductEnum productEnum) { Supplier<AbstractFinanceProduct> productSupplier = PRODEUC_MAP.get(productEnum); if (productSupplier != null) { //這裏每次調用都生成新的對象,map的value獲得的是一個函數式接口的lambda實現,每次都new新對象出來。 return productSupplier.get(); } throw new IllegalArgumentException("No such product" + productEnum.name()); } }
若是不想所建立的對象都是子類繼承父類,高度耦合的(實際也不多這樣),但在實際開發中又須要常常用到建立對象,能夠試試下面這種方式。
這個是我在開發中所運用到的,項目須要大量調用淘寶的接口,淘寶請求參數的對象又有不一樣的屬性,即調用淘寶線上不一樣的接口,都須要有不一樣的入參對象DTO,因此這些對象都不是繼承的關係,這裏用簡單工廠模式來建請求淘寶接口的對象。
UML類圖:
spa
/** * 請求報文,T 攜帶簡單工廠所建立的不一樣對象 * @author Fiuty */ public class RequestDTO <T>{ private T payload;
public class Animal { private String name; public Animal(String name) { this.name = name; }
public class People { private String name; public People(String name) { this.name = name; } }
工廠接口類,建對象的方法,統一返回RequestDTO<T>,在泛型中返回所需的對象,而這些對象都不是子類繼承父類,高度耦合。.net
public interface SimpleFactoryAdvanceService { RequestDTO<People> createPeople(String name); RequestDTO<Animal> createAnimal(String name); }
工廠實現類設計
public class SimpleFactoryAdvanceServiceImpl implements SimpleFactoryAdvanceService { @Override public RequestDTO<People> createPeople(String name) { return new RequestDTO<>(new People(name)); } @Override public RequestDTO<Animal> createAnimal(String name) { return new RequestDTO<>(new Animal(name)); } }
最後調用工廠實現類來生產咱們所需的對象:
public class SimpleFactoryPatternAdvance { public static void main(String[] agrs) { SimpleFactoryAdvanceServiceImpl factory = new SimpleFactoryAdvanceServiceImpl(); RequestDTO<Animal> animalRequest = factory.createAnimal("特朗普"); RequestDTO<People> peopleRequest = factory.createPeople("上帝"); System.out.println("動物的名字是:"+animalRequest.getPayload().getName()); System.out.println("人類的名字是:"+peopleRequest.getPayload().getName()); } }
參考資料:
http://www.javashuo.com/article/p-mswxlyip-nq.html《Java8 實戰》