靜態(tài)工廠
在最早的《DesignPattern》這本書中 靜態(tài)工廠是沒有的 工廠系列就兩個(gè)模式 工廠方法和抽象工廠,但是也有人說靜態(tài)工廠是工廠模式
什么是工廠历筝?
1.任何可以產(chǎn)生(new)對象的方法或類友鼻,都可以稱之為工廠
2.看到1個(gè)方法 它的返回值return是1個(gè)對象 就可以稱之為1個(gè)工廠
所以單例也是一種工廠傻昙,單例模式的 getInstance 就是拿到1個(gè)對象 所以有人把單例模式 稱為靜態(tài)工廠
為什么要工廠? 我們已經(jīng)可以new產(chǎn)生對象了彩扔,為什么還要工廠妆档?
工廠可以靈活控制生產(chǎn)過程,可以加權(quán)限虫碉、修飾decorate贾惦、日志log等
我們先寫1個(gè)類 Car
public class Car {
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
然后我們再創(chuàng)建1個(gè)Main類 new出來1個(gè)Car
public class Main {
public static void main(String[] args) {
Car c = new Car();
c.go();
}
}
現(xiàn)在開的是Car車 我明天想開Plane飛機(jī)怎么辦? 可以定制交通工具(實(shí)現(xiàn)類 )嗎敦捧?
我們當(dāng)然可以再創(chuàng)建1個(gè)Plane飛機(jī)類须板,然后main方法去創(chuàng)建1個(gè)飛機(jī)
public class Plane {
public void go(){
System.out.println("Plane fly xixixixixixixi....");
}
}
public class Main {
public static void main(String[] args) {
// Car c = new Car();
// c.go();
Plane p = new Plane();
p.go();
}
}
如果我以后想開火車Train,船Boat等等兢卵?難道還是像這樣 1個(gè)1個(gè)擴(kuò)展嗎习瑰?代碼太多了,既要新建1個(gè)類秽荤,還要修改main方法里的內(nèi)容甜奄,我想少點(diǎn)柠横,怎么辦?
我們可以創(chuàng)建1個(gè)接口Moveable ,其他的所有交通工具去實(shí)現(xiàn)這個(gè)接口
public interface Moveable {
void go();
}
public class Plane implements Moveable{
public void go(){
System.out.println("Plane fly xixixixixixixi....");
}
}
public class Car implements Moveable{
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
這樣main方法可以利用多態(tài)课兄,只用改new后面的類就行了牍氛,不管調(diào)用
public class Main {
public static void main(String[] args) {
Moveable m = new Plane();
m.go();
}
}
代碼只用修改1個(gè)地方,不用像第1種方法烟阐,要?jiǎng)h除修改至少2段
需求又來了搬俊,我想任意定制旅途過程 怎么辦?
實(shí)際中的應(yīng)用 我new 1個(gè)交通工具后 我要求你必須控制權(quán)限 那么我的代碼要修改在Plane類里 必須要來回的變曲饱;我可以把 產(chǎn)生對象的這個(gè)過程 不用new 我交給1個(gè)工廠方法
1.簡單工廠VehicleFatory
創(chuàng)建1個(gè)VehicleFactory類 里面有幾個(gè)方法 比如返回Car對象的 createCar()方法 在這個(gè)方法里面 我們可以對它進(jìn)行日志處理 權(quán)限處理等悠抹;而且VehicleFactory類除了 產(chǎn)生Car外 還可以產(chǎn)生Plane等
public class VehicleFactory {
public Car createCar(){
return new Car();
}
public Plane createPlane(){
return new Plane();
}
}
但是這種方法不太好 因?yàn)樗m然很簡單 但是可擴(kuò)展性不太好 當(dāng)我們新添加1種交通工具 火車train的時(shí)候 里面就要新添加新的createTrain方法 而且里面的 權(quán)限處理的操作也是寫死的
針對每個(gè)產(chǎn)品做1個(gè)工廠
對于Car來說 我加1個(gè)CarFactory類
public class CarFactory {
public Car createCar(){
System.out.println("a car created!");
return new Car();
}
}
如果我們想用CarFactory的話 main方法要這樣寫
public class Main {
public static void main(String[] args) {
Moveable m = new CarFactory().createCar();
m.go();
}
}
想來個(gè)Plane的話 就寫個(gè)PlaneFactory().createPlane() 想來個(gè)broom的話 就寫個(gè)BroomFactory().createBroom()
但是問題來了 當(dāng)我們要添加一種新的交通工具的時(shí)候 我們首先得把它的工廠做出來PlaneFactory,broomFactory 接下來 我還要把代碼改一下 更麻煩
總結(jié)一下:任意定制交通工具扩淀,我們可以 繼承Moveable楔敌;任意定制生產(chǎn)過程,我們可以Moveable XXXFactory.create()
2.抽象工廠
因?yàn)榻谐橄蠊S驻谆,所以是任意定制產(chǎn)品一族(不只1種系列產(chǎn)品)卵凑,叫abstractFactory 更加抽象這個(gè)問題。
比如:現(xiàn)在是這樣的 胜臊,作為1個(gè)司機(jī) 我開著一輛車 車還在跑勺卢,然后這個(gè)司機(jī),他手里還持有1個(gè)武器AK47 就叫AK47類象对,他還可以吃一點(diǎn)面包Bread 有個(gè)面包類
AK47類可以開槍黑忱,Brand類可以打印品牌
public class AK47 {
public void shoot(){
System.out.println("tutututututu.....");
}
}
public class Brand {
public void printName(){
System.out.println("wdm");
}
}
那么這樣我就模擬了 很多類產(chǎn)品 Car,AK47,Bread ,其實(shí)這個(gè)是 產(chǎn)品簇的概念 我們有沒有一種方式 可以靈活的指定 來擴(kuò)展新的產(chǎn)品簇勒魔,比如現(xiàn)在我來一個(gè)人是魔法師 他騎的是掃帚Broom 吃的是蘑菇Mushroom 它的魔法棒MagicStick可以發(fā)電 這樣當(dāng)新的產(chǎn)品加進(jìn)來的時(shí)候 代碼不用改太多呢甫煞?
可以的 我們可以new 1個(gè)AbstractFactory. 這個(gè)抽象工廠 可以生產(chǎn) 1系列產(chǎn)品 他可以生產(chǎn)食物,武器,交通工具
public abstract class Food {
abstract void printName();
}
public abstract class Weapon {
abstract void shoot();
}
public abstract class Vehicle {
abstract void go();
}
我們假設(shè) 這個(gè)抽象工廠會(huì)產(chǎn)生 3類產(chǎn)品;第1類是Food冠绢,第2類是Vehicle抚吠,第3類是Weapon,他們都可以返回對應(yīng)的對象弟胀,可以生成抽象的產(chǎn)品
public abstract class AbstractFactory {
abstract Food createFood();
abstract Vehicle createVehicle();
abstract Weapon createWeapon();
}
然后我們讓所有的不同類別的產(chǎn)品 去繼承
現(xiàn)代人的工具簇就是 Weapon對應(yīng)AK47,Food對應(yīng)Bread楷力,Vehicle對應(yīng)Car
//現(xiàn)代人的工具包
public class Car extends Vehicle{
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
public class Brand extends Food{
public void printName(){
System.out.println("wdm");
}
}
public class AK47 extends Weapon{
public void shoot(){
System.out.println("tutututututu.....");
}
}
我們做1個(gè)現(xiàn)代工廠ModernFactory,幫我們?nèi)ドa(chǎn)這些東西孵户,而不必自己去new
public class ModernFactory extends AbstractFactory {
@Override
Food createFood() {
return new Brand();
}
@Override
Vehicle createVehicle() {
return new Car();
}
@Override
Weapon createWeapon() {
return new AK47();
}
}
魔法師的工具簇就是 Weapon對應(yīng)MagStick,Food對應(yīng)MushRoom萧朝,Vehicle對應(yīng)Broom
//魔法師的工具包
public class Broom extends Vehicle {
public void go(){
System.out.println("Broom flying shushushus....");
}
}
public class MushRoom extends Food {
public void printName(){
System.out.println("毒蘑菇");
}
}
public class MagicStick extends Weapon{
public void shoot(){
System.out.println("dian dian dian dian....");
}
}
魔法師就是魔法工廠MagicFactory,幫我們?nèi)ドa(chǎn)這些東西
public class MagicFactory extends AbstractFactory{
@Override
Food createFood() {
return new MushRoom();
}
@Override
Vehicle createVehicle() {
return new Broom();
}
@Override
Weapon createWeapon() {
return new MagicStick();
}
}
現(xiàn)在延届,我們main方法里面代碼就簡單了
之間我們需要1個(gè)1個(gè)new
Car c =new Car();
c.go();
AK47 w=new AK47();
w.shoot();
Bread b=new Bread();
b.printName();
現(xiàn)在不需要了 直接調(diào)用現(xiàn)代工廠里的方法就行
AbstractFactory f = new ModernFactory();
Vehicle c = f.createVehicle();
Weapon w = f.createWeapon();
Food b = f.createFood();
而且修改代碼恨少剪勿,你想改成 魔法世界工廠 你就把new 后面改一下 下面的都不用改 new MagicFactory(),同理方庭,火星世界 就改成火星一簇 寫個(gè)MarsFactory 去實(shí)現(xiàn)里面的火星武器厕吉,食物酱固,機(jī)器
注意:這個(gè)工廠里用的都是繼承,不是接口的實(shí)現(xiàn)头朱,因?yàn)楣S里的產(chǎn)生的食品一般是現(xiàn)實(shí)中存在的运悲,但是它不是具體的某個(gè)食物,所以用抽象類比較合適项钮,而接口更加側(cè)重于這個(gè)東西的屬性班眯,moveable表示它這個(gè)東西可以動(dòng),comparable表示這個(gè)東西可以比較烁巫,所以從語義上用抽象類更加合適署隘,形容詞用接口,名詞用抽象類
比較 工廠方法 和抽象工廠
工廠方法:在產(chǎn)品擴(kuò)展時(shí)亚隙,比較方便
有Car 有Food 有AK47 以后比如說 還有帽子等等 非常方便
抽象工廠:然后 在產(chǎn)品簇上擴(kuò)展比較方便 但是在產(chǎn)品上擴(kuò)展不好擴(kuò)展
所以這個(gè)是兩個(gè)維度上的擴(kuò)展磁餐,1個(gè)是產(chǎn)品一簇維度上 偏于擴(kuò)展; 另一個(gè)是產(chǎn)品單一維度上 好擴(kuò)展 都有自己的局限性
總結(jié)一下:
簡單工廠vs靜態(tài)工廠vs工廠方法vs抽象工廠
簡單工廠:我們隨便1個(gè)方法 只要createCar什么東西 返回的是1個(gè)對象 那么它就是簡單工廠
靜態(tài)工廠:靜態(tài)的方法Static產(chǎn)生 比如單例的getInstance 就是1個(gè)靜態(tài)工廠
工廠方法FactoryMethod:產(chǎn)品維度上擴(kuò)展 很方便
抽象工廠:產(chǎn)品一簇進(jìn)行擴(kuò)展
我們經(jīng)嘲⑵可以用抽象工廠來完成一鍵風(fēng)格替換诊霹,比如1個(gè)人物,我可以換它的聲音渣淳,皮膚脾还,動(dòng)作等