簡單工廠模式
先來看一個問題,我們要給手機買一個手機殼,因為各種手機形狀不一致,所以手機殼有很多種類,下面用代碼的形式處理這個問題
String phoneName = "xxx";
// 所有的shell都是繼承自PhoneShell,這里偷個懶就不寫了。
PhoneShell shell = null;
if("Iphone".equals(phoneName)){
shell = new IphoneShell();
}else if("huawei".equals(phoneName)){
shell = new HuaweiShell();
}....
在這個例子的代碼實現里,我們用到了很多的if else,不是說不能用if else 但是過多的if else堆砌會顯得代碼不是那么的簡潔,這時我們把這些判斷邏輯封裝起來
public class PhoneShellFactory{
public static PhoneShell getPhoneShell(String phoneName){
if("Iphone".equals(phoneName)){
return new IphoneShell();
}else if("huawei".equals(phoneName)){
return new HuaweiShell();
}...
}
}
再次編寫解決這個問題的代碼,代碼就成了下面這個樣子
String phoneName = "xxx";
PhoneShell shell = PhoneShellFactory.getPhoneShell(phoneName);
代碼就變得十分簡潔了,但是還是有問題,雖然原本的if else沒了,但是我們在編寫PhoneShellFactory這個類的時候還是寫了if else啊,這不是自欺欺人嗎?復雜度不會消失,只會轉移,所以我們把根據手機類型獲得手機殼的過程封裝在一個類之中,這像不像你去手機店買手機殼,只需要告訴店家你的手機類型,店家就會給你找來合適的手機殼,而不是你自己挨個去找,這就是簡單工廠模式,也叫做靜態工廠模式,因為只有一個獲得商品的靜態方法,所以沒必要每次都實例化工廠對象,簡單工廠模式是有違開閉原則的,開閉原則簡單來說就是,允許對代碼進行擴展,但是不允許對原有的代碼進行修改,所以如果我們要增加商店提供的手機殼的種類就要修改PhoneShellFactory的代碼,這就有違開閉原則。簡單工廠模式也並不是每次都要創建新的對象,也可以在代碼邏輯里加入緩存,這里就不作贅述。
工廠方法模式
前面說的簡單工廠方法是有違開閉原則的,相反的,工廠方法模式是不違背開閉原則的,但是工廠方法並不是簡單工廠的進階版本,他倆的着重點是有區別的,首先我們定義一個ShellFactory接口
public interface ShellFactory {
public PhoneShell getShell();
}
接下來我們定義兩個實現ShellFactory的類
public class IphoneShellFactory extends ShellFactory {
@Override
public PhoneShell getShell() {
return new IphoneShell();
}
}
public class HuaweiShellFactory extends ShellFactory {
@Override
public PhoneShell getShell() {
return new HuaweiShell();
}
}
下面我們編寫購買手機殼的代碼
ShellFactory sf = new IphoneShellFactory();
PhoneShell shell = sf.getShell();
類圖如下
工廠模式滿足了開閉原則,如果我們需要增加一個手機殼的種類,只需要編寫一個實現ShellFactory的類即可,但是如果想要根據傳入的手機類型創建手機殼工廠,還是需要if else邏輯判斷,所以前面說工廠方法並不是簡單工廠的進階版本,他倆的着重點是有區別的,看完上面的代碼可能會有一個疑問,既然都知道是要iphone的手機殼那我們直接new 一個IphoneShell不就行了,還用整這么麻煩嗎?還要先new 一個IphoneShellFactory然后調用getShell才能得到IphoneShell簡直不要太復雜,其實上面的代碼只是簡單的說明了工廠方法模式滿足了開閉原則,工廠方法模式的着重點其實是隱藏創建產品的細節,且不一定每次都會真正創建產品,還是用代碼來說,我們來一個實現ShellFactory的類
public class XiaomiShellFactory implements ShellFactory {
@Override
public PhoneShell getShell() {
PhoneShell shell = new XiaomiShell();
shell.rePrint(); // 手機殼重新噴塗顏色;
return shell;
}
}
這里我們在getShell方法里,加了一點細節,在實際的業務中可能創建一個產品對象有很多的細節操作,工廠方法模式的意義就是隱藏這些細節,再舉一個簡單的例子,比如我們買手機,同一款手機會有很多可變的參數,比如顏色,RAM,ROM,
public class Mi10Blue6$256PhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
Phone phone = new Mi10();
phone.printColor("Blue");
phone.setRAM(6);
phone.setROM(256);
return phone
}
}
當然這個例子還是有點單薄,操作比較簡單,也可以用構造函數實現,這里只是理解一下思想,不必較真,真實的業務里可能不僅僅是對POJO屬性的簡單操作。那不一定每次都會真正創建產品又是什么意思呢,還是用代碼來說
public class XiaomiShellFactory implements ShellFactory {
static Stack stack = new Stack();
static{
// 櫃台上一開始可能就擺放着一些手機殼,可能是熱賣的,也可能是拿給別的顧客看,顧客沒買的。
// 從倉庫取手機殼相當於創建一個新的手機殼, 從櫃台獲取相當於沒有新創建一個
stack.push(new XiaomiShell());
}
@Override
public PhoneShell getShell() {
if(stack.isEmpty()){
return new XiaomiShell();
}else{
return (PhoneShell) stack.pop();
}
}
}
這里對應到實際的業務中可能就是相應的緩存。
抽象工廠
工廠方法模式只是生產一個對象也就是一個產品,有時業務特別復雜,需要一個工廠得到多個產品怎么辦?這時候就該抽象工廠出場了,從工廠方法模式來理解,一個工廠能創建一類產品,如果需要創建多類產品,那就是需要創建工廠的工廠,下面上代碼,首先創建接口ElectronicsmakersFactory
public interface ElectronicsmakersFactory{
public Phone getPhone();
public Computer getComputer();
}
接着創建實現類
public XiaoMiFactory implements ElectronicsmakersFactory{
@Override
public Phone getPhone() {
return new Mi10PhoneFactory.getPhone();
}
@Override
public Computer getComputer() {
return new MiBookComputerFactory.getComputer();
}
}
public AppleFactory implements ElectronicsmakersFactory{
@Override
public Phone getPhone() {
return new Ip11PhoneFactory.getPhone();
}
@Override
public Computer getComputer() {
return new MacBookProComputerFactory.getComputer();
}
}
調用時的代碼
ElectronicsmakersFactory ef = new XiaoMiFactory();
Phone phone = ef.getPhone();
Computer computer = ef.getComputer();
類圖如下
總結
簡單工廠模式主要注重於隱藏處理邏輯,工廠方法模式注重於隱藏裝配類的細節,抽象工廠模式主要是處理復雜的業務邏輯,層級比較多。