前言
工廠模式是創建型模式,使我們常用/常見的模式之一。多用于需要生成復雜對象的地方。用new就可以完成創建的對象就無需使用。工廠模式降低了對象之間的耦合度,由于工廠模式依賴抽象的架構,實例化的任務交由子類去完成,所以有很好的擴展性。
工廠模式
定義:一個用于創建對象的接口,讓子類決定實例化哪個類
工廠模式一般也就兩大類:
普通工廠模式:生產具體的產品,創建的產品是類(Class)。
抽象工廠模式:生產抽象的產品,創建的產品是接口(Interface)。
一開始你可能理解不上來,當你看完這篇文章,你理解了,其實他們并不復雜,我們先來看一個普通工廠的例子
(這里擴展一點,雖然普通工廠表面上創建的是抽象類,但java特性里抽象類是不能被實例化的。我沒每次創建的時候,實際上是以匿名內部類的方式創建。實際是它繼承并創建的一個新的類。所以它僅僅是一個普通工廠)
普通工廠模式舉例
我們舉一個生產Nokia手機的例子。
public abstract class NokiaPhone {
public abstract void powerOnPhone();
}
先試定義了一個抽象類,抽象出方法powerOnPhone(),模擬手機開機的動作。(ps:抽象類作用簡單點說就是抽象出一些方法,需要子類去實現,自己不能實現。起到一個抽象的作用)
然后我們定義具體的手機
public class Nokia5200 extends NokiaPhone {
@Override
public void powerOnPhone() {
Log.d("Factory","Nokia5200 power on");
}
}
public class NokiaN97 extends NokiaPhone{
@Override
public void powerOnPhone() {
Log.d("Factory","NokiaN97 power on");
}
}
然后我們定義了具體的手機Nokia5200和NokiaN97兩款手機。并實現了抽象方法powerOnPhone
現在產品定義好了,我們就要定義工廠了,首先我們也抽象出工廠的方法
public abstract class Factory {
public abstract <T extends NokiaPhone> T createNokia(Class<T> clz);
}
工廠的方法無非就是生產手機,所以我們抽象出來了createNokia方法,現在我們來定義工廠
public class NokiaFactory extends Factory {
@Override
public <T extends NokiaPhone> T createNokia(Class<T> clz) {
NokiaPhone nokiaPhone = null;
try {
nokiaPhone = (NokiaPhone) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) nokiaPhone;
}
}
NokiaFactory工廠也很簡單就實現了抽象方法createNokia,來生產不同的手機。這里我們使用了反射方法
nokiaPhone = (NokiaPhone) Class.forName(clz.getName()).newInstance();
這句話的意思是通過類名(ClassName)來實例化具體的類,用的是反射機制來實現。
然后我們來看看我們怎么用工廠生產手機。
NokiaFactory nokiaFactory = new NokiaFactory();
Nokia5200 nokia5200 = nokiaFactory.createNokia(Nokia5200.class);
NokiaN97 nokiaN97 = nokiaFactory.createNokia(NokiaN97.class);
我們用工廠創建了兩個手機,一個nokia5200,一個nokiaN97。然后我們開機試試
nokia5200.powerOnPhone();
nokiaN97.powerOnPhone();
看log
D/Factory: Nokia5200 power on
D/Factory: NokiaN97 power on
至此,一個工廠模式就寫完了,可以看到工廠模式的代碼結構其實很簡單。有的讀者可能會想為啥NokiaFactory為啥要用反射呢,其實用反射主要是為了代碼簡潔,如果不這么寫,你可能像下面的代碼這樣寫
// 方案一
public class NokiaFactoryNokia5200 extends Factory {
@Override
public <T extends NokiaPhone> T createNokia() {
Nokia5200 nokia5200 = new Nokia5200();
return (T) nokia5200;
}
}
public class NokiaFactoryNokiaN97 extends Factory {
@Override
public <T extends NokiaPhone> T createNokia() {
NokiaN97 nokiaN97 = new NokiaN97();
return (T) nokiaN97;
}
}
// 方案二
public class NokiaFactory extends Factory {
@Override
public <T extends NokiaPhone> T createNokia(Class<T> clz) {
Log.d("Factory",clz.getSimpleName());
if (clz.getSimpleName().equals("Nokia5200")) {
Nokia5200 nokia5200 = new Nokia5200();
return (T) nokia5200;
} else if (clz.getSimpleName().equals("NokiaN97")) {
NokiaN97 nokiaN97 = new NokiaN97();
return (T) nokiaN97;
}
return null;
}
}
普通工廠模式小結
1、上面兩種方案,一是為每個手機單獨創建一個工廠,或者通過帶入的class來選擇創建都能實現,但是如果手機型號過多,代碼就顯得很長,當然最好還是用反射的方法,這里只是為了進行一個說明。
2、上面NokiaFactoryNokia5200、NokiaFactoryNokiaN97這種情況也有適合用這種方式的地方。我們下面講解抽象工廠的時候就會用不同工廠對應不同產品的方式來創建。并非一定是反射的方法。
3、最開始的例子還可以省略抽象方法,抽象方法只是為了更具體化,不過不建議這么做,抽象方法使我們的NokiaPhone更規范。代碼可讀性也更好。
4、普通工廠模的創建的產品是具體的類,這個例子的產品是NokiaPhone.class,雖然它是一個抽象類,但使用時已經創建的匿名內部類是一個具體的類。
抽象工廠模式例子
抽象工廠我們舉例一個生產Iphone零件的例子。
我們先定義產品,這里是生產零件,我們定義兩個抽象產品,一個CPU,一個電池。這里我把兩個接口寫在了一起,當然你也可以分開寫成兩個。
public interface component {
public interface CPU {
void showCpuName();
}
public interface Battery {
void showBatteryCapacity();
}
}
然后我們定義CPU的具體產品,一個A9,一個A10
public class A9 implements component.CPU {
@Override
public void showCpuName() {
Log.d("AbstractFactory","A9");
}
}
public class A10 implements component.CPU {
@Override
public void showCpuName() {
Log.d("AbstractFactory","A10");
}
}
然后是兩種電池產品,一個1000ma,一個1200ma
public class Battery1000ma implements component.Battery {
@Override
public void showBatteryCapacity() {
Log.d("AbstractFactory","battery is 1000ma");
}
}
public class Battery1200ma implements component.Battery {
@Override
public void showBatteryCapacity() {
Log.d("AbstractFactory","battery is 1200ma");
}
}
產品定義好了,我們來定義工廠了,依舊先用抽象類,抽象出工廠類的方法
public abstract class Factory {
public abstract component.CPU createCPU();
public abstract component.Battery createBattery();
}
注意一點這里的抽象方法跟抽象工廠模式并無實際關系,不是因為這里使用抽象類而因此叫抽象工廠模式,而是因為工廠模式生產的產品。一個是component.CPU,一個是component.Battery。他們兩個都是接口,都是抽象出來的,抽象工廠模式因此而來。
雖然java特性里,抽象類和接口不都能實例化。都是創建匿名內部類方式來創建對象,但普通工廠創建的是抽象類,還是對象的一種描述,而抽象工廠思想上還是創建的接口。接口編程,由此特性所以它叫抽象工廠。
接著我們看具體工廠的實現,這里我們將用不同的工廠對應不同的產品來舉例
public class IPhone6Factory extends Factory {
@Override
public component.CPU createCPU() {
return new A9();
}
@Override
public component.Battery createBattery() {
return new Battery1000ma();
}
}
public class Iphone7Factory extends Factory {
@Override
public component.CPU createCPU() {
return new A10();
}
@Override
public component.Battery createBattery() {
return new Battery1200ma();
}
}
1、可以看到IPhone6Factory和Iphone7Factory兩個工廠模式他們創建的產品相同,都是創建CPU和Battery這兩個抽象產品。而這兩個抽象產品又可以是同接口不同子類實例。
抽象工廠模式小結
1、抽象工廠模式創建的產品是接口,抽象出來的。
2、上面的例子其實跟普通工廠模式例子沒太大的差別,除了產品不同,實現的思想都是一樣的,只是這里用了不同的工廠對應不同的產品。普通工廠模式也可以這樣用。
3、抽象工廠有一個顯著的優點是分離接口與實現,用戶根本不知道具體的實現是誰,客戶僅僅是面向接口編程,使其從產品實現解耦,抽象工廠模式在切換產品類的時候更加靈活容易。
結束語
1、現在理解文章最開始的那句話是不是很好理解了
普通工廠模式:生產具體的產品,創建的產品是類(Class)
抽象工廠模式:生產抽象的產品,創建的產品是接口(Interface)
2、工廠模式的優點在上述兩個例子的小結中已經闡述,工廠模式的缺點也比較明顯,就是不太容易擴展新的產品類,需要去改具體的產品類和工廠類。
3、雖然美中不足,但工廠模式是運用非常廣泛的一種模式。值得大家學習使用。