Java设计模式之工厂模式最详解(类图+源码)
?2、工廠模式
例子:一盒咖啡店點(diǎn)餐系統(tǒng):設(shè)計(jì)一個(gè)咖啡類(Coffee),并定義其兩個(gè)子類(美事咖啡【AmericanCoffee】和拿鐵咖啡【LatteCoffee】);再設(shè)計(jì)一個(gè)咖啡店類(CoffeeStore),咖啡店具有點(diǎn)咖啡的功能。
系統(tǒng)類圖
//抽象咖啡類 public abstract class Coffee {public abstract String getName();//加糖public void addsugar(){System.out.println("加糖");}//加奶public void addMilk(){System.out.println("加奶");} }//美式咖啡 public class AmericanCoffee extends Coffee{@Overridepublic String getName() {return "美式咖啡";}} //拿鐵咖啡 public class LattaCoffee extends Coffee{@Overridepublic String getName() {return "拿鐵咖啡";} } public class CoffeeStore {public Coffee orderCoffee(String type){//聲明Coffee類型的變量,根據(jù)不同類型創(chuàng)建不同的Coffee子類對(duì)象Coffee coffee=null;if("american".equals(type)){coffee=new AmericanCoffee();}else if("latta".equals(type)){coffee=new LattaCoffee();}else{throw new RuntimeException("對(duì)不起,您所點(diǎn)的咖啡沒(méi)有");}//加配料coffee.addMilk();coffee.addsugar();return coffee;} }public class Client {public static void main(String[] args) {//1、創(chuàng)建咖啡店類CoffeeStore store=new CoffeeStore();Coffee coffee = store.orderCoffee("american");System.out.println(coffee.getName());} } 結(jié)果 加奶 加糖 美式咖啡Process finished with exit code 0在Java語(yǔ)言中,萬(wàn)物皆對(duì)象,這些對(duì)象都需要?jiǎng)?chuàng)建,如果創(chuàng)建的時(shí)候直接new該對(duì)象,就會(huì)對(duì)該對(duì)象耦合嚴(yán)重,假如我們要更換對(duì)象,所有new對(duì)象的地方都需要修改一遍,這顯然違背了軟件設(shè)計(jì)的開閉原則。如果我們使用工廠來(lái)生產(chǎn)對(duì)象,我們就只和工廠打交道就可以了,徹底和對(duì)象解耦,如果要更換對(duì)象,直接在工廠里更換該對(duì)象即可,達(dá)到與對(duì)象解耦的目的。所以說(shuō),工廠模式最大的優(yōu)點(diǎn)是:解耦
工廠模式中三種工廠的使用
簡(jiǎn)單工廠模式(不屬于GOF的23種經(jīng)典設(shè)計(jì)模式)
工廠方法模式
抽象工廠模式
簡(jiǎn)單工廠模式:簡(jiǎn)單工廠模式不是一種設(shè)計(jì)模式,反而比較像是一種編程習(xí)慣。
簡(jiǎn)單工廠模式包含的角色
抽象產(chǎn)品:定義了產(chǎn)品的規(guī)范。描述了產(chǎn)品的主要特性和功能
具體產(chǎn)品:實(shí)現(xiàn)或者繼承抽象產(chǎn)品的子類
具體工廠:提供了創(chuàng)建產(chǎn)品的方法,調(diào)用者通過(guò)該方法來(lái)獲取產(chǎn)品
用簡(jiǎn)單工廠對(duì)咖啡點(diǎn)餐系統(tǒng)進(jìn)行改進(jìn)
?具體代碼
//抽象咖啡類 public abstract class Coffee {public abstract String getName();//加糖public void addsugar(){System.out.println("加糖");}//加奶public void addMilk(){System.out.println("加奶");} }//拿鐵咖啡 public class LattaCoffee extends Coffee {@Overridepublic String getName() {return "拿鐵咖啡";} }//美式咖啡 public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}public class SimpleCoffeeFactory {public Coffee createCoffee(String type){//聲明Coffee類型的變量,根據(jù)不同類型創(chuàng)建不同的coffee子類對(duì)象Coffee coffee=null;if("american".equals(type)){coffee=new AmericanCoffee();}else if("latta".equals(type)){coffee=new LattaCoffee();}else{throw new RuntimeException("對(duì)不起,您所點(diǎn)的咖啡沒(méi)有");}return coffee;} }public class CoffeeStore {public Coffee orderCoffee(String type){SimpleCoffeeFactory factory=new SimpleCoffeeFactory();//調(diào)用生產(chǎn)咖啡的方法Coffee coffee = factory.createCoffee(type);coffee.addMilk();coffee.addsugar();return coffee;} }public class Client {public static void main(String[] args) {CoffeeStore store=new CoffeeStore();Coffee coffee = store.orderCoffee("latta");System.out.println(coffee.getName());} } 結(jié)果 加奶 加糖 拿鐵咖啡Process finished with exit code 0工廠(factory)處理創(chuàng)建對(duì)象的細(xì)節(jié),一旦有了SimpleCoffeeFactory,CoffeeStore類中的orderCoffee()就變成此對(duì)象的客戶,后期如果需要coffee對(duì)象直接從工廠中獲取即可。這樣就解除了和Coffee實(shí)現(xiàn)類的耦合,同時(shí)又產(chǎn)生了新的耦合。CoffeeStore對(duì)象和SimpleCoffeeFactory工廠對(duì)象的耦合,工廠對(duì)象和商品對(duì)象的耦合。
后期再加新品種的咖啡,勢(shì)必要修改SimpleCoffeeFactory的代碼,違反了開閉原則。工廠類的客戶端可能有很多,比如創(chuàng)建美團(tuán)外賣,這樣只需要修改工廠類的代碼,省去其他操作。
簡(jiǎn)單工廠模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):封裝了創(chuàng)建對(duì)象的過(guò)程,可以通過(guò)參數(shù)直接獲取對(duì)象。把對(duì)象的創(chuàng)建和業(yè)務(wù)邏輯層分開,這樣以后就避免了修改客戶代碼,如果要實(shí)現(xiàn)新產(chǎn)品直接修改工廠類,而不需要在源代碼中修改,這樣就降低了客戶代碼修改的可能性,更加容易擴(kuò)展。
缺點(diǎn):增加新產(chǎn)品時(shí)還是需要修改工廠類的代碼,違反了“開閉原則”。
對(duì)簡(jiǎn)單工廠模式的擴(kuò)展
靜態(tài)工廠:開發(fā)過(guò)程中有一部分人將工廠中的創(chuàng)建對(duì)象的功能定義為靜態(tài)的,這個(gè)就是靜態(tài)工廠模式,它也不是23種設(shè)計(jì)模式中的
public class SimpleCoffeeFactory {public static Coffee createCoffee(String type){//聲明Coffee類型的變量,根據(jù)不同類型創(chuàng)建不同的coffee子類對(duì)象Coffee coffee=null;if("american".equals(type)){coffee=new AmericanCoffee();}else if("latta".equals(type)){coffee=new LattaCoffee();}else{throw new RuntimeException("對(duì)不起,您所點(diǎn)的咖啡沒(méi)有");}return coffee;} }public class CoffeeStore {public Coffee orderCoffee(String type){//調(diào)用生產(chǎn)咖啡的方法Coffee coffee = SimpleCoffeeFactory.createCoffee(type);coffee.addMilk();coffee.addsugar();return coffee;} }?工廠方法模式:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪個(gè)產(chǎn)品對(duì)象。工廠方法使一個(gè)產(chǎn)品類的實(shí)例化延遲到其工廠的子類。
工廠方法模式中的主要角色
抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,調(diào)用者通過(guò)它訪問(wèn)具體工廠的工廠方法來(lái)創(chuàng)建產(chǎn)品。
具體工廠(Concrete Factory):主要是實(shí)現(xiàn)抽象工廠中的抽象方法,完成具體產(chǎn)品的創(chuàng)建。
抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能
具體產(chǎn)品(ConcreteProduct):實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來(lái)創(chuàng)建,它同具體工廠之間一一對(duì)應(yīng)。
使用工廠方法模式對(duì)咖啡點(diǎn)餐系統(tǒng)進(jìn)行改進(jìn)
類圖
public abstract class Coffee {public abstract String getName();//加糖public void addsugar(){System.out.println("加糖");}//加奶public void addMilk(){System.out.println("加奶");} } //美式咖啡 public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}//拿鐵咖啡 public class LattaCoffee extends Coffee {@Overridepublic String getName() {return "拿鐵咖啡";} }public interface CoffeeFactory {//創(chuàng)建咖啡對(duì)象的方法Coffee createCoffee(); }public class AmericanCoffeeFactory implements CoffeeFactory{@Overridepublic Coffee createCoffee() {return new AmericanCoffee();} }public class LattaCoffeeFactory implements CoffeeFactory{@Overridepublic Coffee createCoffee() {return new LattaCoffee();} }public class CoffeeStore {private CoffeeFactory factory;public void setFactory(CoffeeFactory factory){this.factory=factory;}public Coffee orderCoffee(){//調(diào)用生產(chǎn)咖啡的方法Coffee coffee = factory.createCoffee();//添加配料coffee.addMilk();coffee.addsugar();return coffee;} } public class Client {public static void main(String[] args) {//創(chuàng)建咖啡店對(duì)象CoffeeStore store=new CoffeeStore();//創(chuàng)建對(duì)象CoffeeFactory factory=new AmericanCoffeeFactory();store.setFactory(factory);//點(diǎn)咖啡Coffee coffee = store.orderCoffee();System.out.println(coffee.getName());} }結(jié)果 加奶 加糖 美式咖啡Process finished with exit code 0?從代碼中可以看到,要增加產(chǎn)品類時(shí)也要相應(yīng)地增加工廠類,不需要修改工廠類的代碼,這樣就解決了簡(jiǎn)單工廠模式的缺點(diǎn)。
工廠方法模式是簡(jiǎn)單工廠模式的進(jìn)一步抽象,由于使用了多態(tài)性,工廠方法模式保持了簡(jiǎn)單工廠模式的優(yōu)點(diǎn),同時(shí)克服了簡(jiǎn)單工廠模式的缺點(diǎn)。
工廠方法模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):用戶只需要直到具體工廠的名稱就可以得到所要的產(chǎn)品,無(wú)須知道產(chǎn)品的具體創(chuàng)建過(guò)程;在系統(tǒng)增加新的產(chǎn)品時(shí)只需要添加具體產(chǎn)品類和對(duì)應(yīng)的具體工廠類,無(wú)須對(duì)原工廠進(jìn)行任何修改,滿足開閉原則。
缺點(diǎn):每增加一個(gè)產(chǎn)品就要增加一個(gè)具體產(chǎn)品類和一個(gè)對(duì)應(yīng)的具體工廠類,這增加了系統(tǒng)的復(fù)雜度。
抽象工廠模式
工廠方法模式中考慮的是一類產(chǎn)品的生產(chǎn),如畜牧場(chǎng)只養(yǎng)動(dòng)物,電視機(jī)廠只生產(chǎn)電視機(jī)等等。這些工廠只生產(chǎn)同種類產(chǎn)品,同種類產(chǎn)品稱為同等級(jí)產(chǎn)品,就是說(shuō):工廠方法模式只考慮生產(chǎn)同等級(jí)的產(chǎn)品,但在現(xiàn)實(shí)生活中許多工廠是綜合型的工廠,能生產(chǎn)多等級(jí)(種類)的產(chǎn)品,如電器廠即生產(chǎn)電視機(jī)又生產(chǎn)洗衣機(jī)或空調(diào)。
抽象工廠的概念:是一種為訪問(wèn)類提供了一個(gè)創(chuàng)建一組相關(guān)或相互依賴對(duì)象的接口,且訪問(wèn)類無(wú)須指定所要產(chǎn)品的具體類型就能得到同族的不同等級(jí)的產(chǎn)品的模式結(jié)構(gòu)。
抽象工廠模式是工廠方法模式的升級(jí)版本,工廠方法模式只生產(chǎn)一個(gè)等級(jí)的產(chǎn)品,而抽象工廠模式可產(chǎn)生多個(gè)等級(jí)的產(chǎn)品。
抽象工廠模式的主要角色
抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,它包含多個(gè)創(chuàng)建產(chǎn)品的方法,可以創(chuàng)建多個(gè)不同等級(jí)的產(chǎn)品。
具體工廠(Concete Factory):主要是實(shí)現(xiàn)抽象工廠中的多個(gè)抽象方法,完成具體產(chǎn)品的創(chuàng)建。
抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能,抽象工廠模式有多個(gè)抽象產(chǎn)品。
具體產(chǎn)品(ConcreteProduct):實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來(lái)創(chuàng)建,它同具體工廠之間是多對(duì)一個(gè)關(guān)系。
例子:咖啡店不僅要生產(chǎn)咖啡還要生產(chǎn)甜點(diǎn),如提拉米蘇、抹茶慕斯等,要是按照工廠模式,需要?jiǎng)?chuàng)建提拉米蘇。抹茶慕斯類、提拉米蘇工廠、抹茶慕斯工廠、甜點(diǎn)工廠類,很容易發(fā)生類爆炸情況。其中拿鐵咖啡、美式咖啡是一個(gè)產(chǎn)品等級(jí),都是咖啡,提拉米蘇、抹茶慕斯又是一個(gè)產(chǎn)品等級(jí);拿鐵咖啡和提拉米蘇是同一產(chǎn)品族(意大利風(fēng)味),美式咖啡和抹茶慕斯是統(tǒng)一產(chǎn)品族(美式風(fēng)味),使用抽象工廠實(shí)現(xiàn)
?
public abstract class Coffee {public abstract String getName();//加糖public void addsugar(){System.out.println("加糖");}//加奶public void addMilk(){System.out.println("加奶");} }//美式咖啡 public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}//拿鐵咖啡 public class LattaCoffee extends Coffee {@Overridepublic String getName() {return "拿鐵咖啡";} }public abstract class Dessert {public abstract void show(); }public class MatchMousse extends Dessert{@Overridepublic void show() {System.out.println("抹茶慕斯");} }public class Trimisu extends Dessert{@Overridepublic void show() {System.out.println("提拉米蘇");} }public interface DessertFactory {//生產(chǎn)咖啡的功能Coffee createCoffee();//生產(chǎn)甜品的功能Dessert createDessert(); }public class AmericanDessertFactory implements DessertFactory{@Overridepublic Coffee createCoffee() {return new AmericanCoffee();}@Overridepublic Dessert createDessert() {return new MatchMousse();} }public class ItalyDessertFactory implements DessertFactory{@Overridepublic Coffee createCoffee() {return new LattaCoffee();}@Overridepublic Dessert createDessert() {return new Trimisu();} }public class Client {public static void main(String[] args) {//創(chuàng)建意大利風(fēng)味甜品工廠對(duì)象ItalyDessertFactory factory=new ItalyDessertFactory();Coffee coffee=factory.createCoffee();Dessert dessert = factory.createDessert();System.out.println(coffee.getName());dessert.show();} }結(jié)果 拿鐵咖啡 提拉米蘇Process finished with exit code 0如果要加同一個(gè)產(chǎn)品族的花,只需要再加一個(gè)對(duì)應(yīng)的工廠類即可,不需要修改其它的類。
抽象工廠模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。
缺點(diǎn):當(dāng)產(chǎn)品族中需要增加一個(gè)新的產(chǎn)品時(shí),所有的工廠類都需要進(jìn)行修改。
抽象工廠模式的使用場(chǎng)景
1、當(dāng)需要?jiǎng)?chuàng)建的對(duì)象是一系列相互關(guān)聯(lián)或相互依賴的產(chǎn)品族時(shí),如電器工廠中的電視機(jī)、洗衣機(jī)、空調(diào)等。
2、系統(tǒng)中有多個(gè)產(chǎn)品族,且所有產(chǎn)品的接口相同,客戶端不依賴產(chǎn)品實(shí)例的創(chuàng)建細(xì)節(jié)和內(nèi)部結(jié)構(gòu)。
模式擴(kuò)展
簡(jiǎn)單工廠+配置文件解除耦合:可以通過(guò)工廠模式+配置文件的方式解除工廠對(duì)象和產(chǎn)品對(duì)象的耦合。在工廠類中加載配置文件中的全類名,并創(chuàng)建對(duì)象進(jìn)行存儲(chǔ),客戶端如果需要對(duì)象,直接進(jìn)行獲取即可。
第一步:定義配置文件
使用properties文件作為配置文件,名稱設(shè)為bean.properties
american=com.ncu.pattern.factory.config_factory.AmericanCoffee latta=com.ncu.pattern.factory.config_factory.LattaCoffee第二步:改進(jìn)工廠類
//抽象咖啡類 public abstract class Coffee {public abstract String getName();//加糖public void addsugar(){System.out.println("加糖");}//加奶public void addMilk(){System.out.println("加奶");} }//美式咖啡 public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}//拿鐵咖啡 public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿鐵咖啡";} }public class CoffeeFactory {//加載配置文件,獲取配置文件中配置的全類,并創(chuàng)建該類的對(duì)象進(jìn)行存儲(chǔ)//1、定義容器對(duì)象存儲(chǔ)咖啡對(duì)象private static HashMap<String,Coffee> map=new HashMap<String,Coffee>();////2、加載配置文件,只需要加載一次static {//2.1創(chuàng)建Properties對(duì)象Properties p=new Properties();//2.2調(diào)用p對(duì)象中的load方法進(jìn)行配置文件的加載InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");try {p.load(is);//從p集合中獲取全類名并創(chuàng)建對(duì)象Set<Object> keys = p.keySet();for(Object key:keys){String className = p.getProperty((String) key);//通過(guò)反射技術(shù)來(lái)創(chuàng)建對(duì)象Class<?> clazz = Class.forName(className);Coffee coffee=(Coffee) clazz.newInstance();//將名稱和對(duì)象存儲(chǔ)到容器中map.put((String)key,coffee);}} catch (Exception e) {e.printStackTrace();}}//根據(jù)名稱獲取對(duì)象public static Coffee createCoffee(String name){return map.get(name);} }public class Client {public static void main(String[] args) {Coffee coffee = CoffeeFactory.createCoffee("american");System.out.println(coffee.getName());} } 結(jié)果 美式咖啡Process finished with exit code 0代碼中靜態(tài)成員變量用來(lái)存儲(chǔ)創(chuàng)建的對(duì)象(鍵存儲(chǔ)的是名稱,值存儲(chǔ)的是相應(yīng)的對(duì)象),而讀取配置文件以及創(chuàng)建對(duì)象寫在靜態(tài)代碼塊中,目的就是只需要執(zhí)行一次。
分析JDK中使用的工廠模式-Collection.iterator方法
單例集合獲取迭代器的方法就使用了工廠方法模式
其類圖結(jié)構(gòu)
?Collection接口是抽象工廠類,ArrayList是具體的工廠類;Iterator接口是抽象商品類,ArrayList類中的Iterator內(nèi)部類是具體的商品類,在具體的工廠類中iterator()方法創(chuàng)建具體的商品類的對(duì)象
總結(jié)
以上是生活随笔為你收集整理的Java设计模式之工厂模式最详解(类图+源码)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 不知道怎么和女孩儿聊天?下面的套路来帮你
- 下一篇: java 抽象工厂 类图_Java设计模