一篇文章帶你入門(mén)java工廠(chǎng)模式
Java設(shè)計(jì)模式-工廠(chǎng)模式
什么是工廠(chǎng)模式?
工廠(chǎng)模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
在工廠(chǎng)模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶(hù)端暴露創(chuàng)建邏輯,并且是通過(guò)使用一個(gè)共同的接口來(lái)指向新創(chuàng)建的對(duì)象。
簡(jiǎn)單編寫(xiě)一個(gè)類(lèi):
1、簡(jiǎn)單工廠(chǎng)模式
本程序非常簡(jiǎn)單就是通過(guò)接口的子類(lèi)為接口對(duì)象實(shí)例化,但是本操作存在什么樣的問(wèn)題呢?
之前一直在強(qiáng)調(diào),主方法或者是主類(lèi)是一個(gè)客戶(hù)端,客戶(hù)端的操作應(yīng)該越簡(jiǎn)單越好。但是在現(xiàn)在的程序之中,有一個(gè)最大的問(wèn)題:客戶(hù)端之中,一個(gè)接口和一個(gè)固定的子類(lèi)綁在一起了。
在本程序之中,最大的問(wèn)題在于耦合上,發(fā)現(xiàn)在主方法之中一個(gè)接口和一個(gè)子類(lèi)緊密耦合在一起,這種方法比較直接,可以簡(jiǎn)單的理解為:A→B,但是這種緊密的方式不方便于維護(hù),所以后來(lái)使用了A→B→C,中間經(jīng)歷了一個(gè)過(guò)渡,這樣一來(lái)B去改變,C去改變,但是A不需要改變,就好比JAVA的JVM一樣:程序→JVM→操作系統(tǒng)。
2、普通工廠(chǎng)模式 UML圖:

源代碼:
ProjectFactory.java
public interface ProjectFactory {
Project getname();
}
BlueFactory.java(ConcreteFactory1)
public class BlueFactory implements ProjectFactory{
@Override
public Project getname() {
// TODO Auto-generated method stub
return new Bluepen();
}
}
RedFactory.java(ConcreteFactory2)
public class RedFactory implements ProjectFactory{
@Override
public Project getname() {
// TODO Auto-generated method stub
return new redPen();
}
}
Project.java(產(chǎn)品類(lèi))
public interface Project {
void name();
}
Bluepen.java(ConcreteProject1)
public class Bluepen implements Project{
@Override
public void name() {
// TODO Auto-generated method stub
System.out.println("這是一個(gè)藍(lán)色的筆");
}
}
RedFactory.java(ConcreteProject2)
public class RedFactory implements ProjectFactory{
@Override
public Project getname() {
// TODO Auto-generated method stub
return new redPen();
}
}
測(cè)試類(lèi)
public class Client {
public static void main(String[] args) {
Project pen = new RedFactory().getname();
pen.name();
Project pen1 = new BlueFactory().getname();
pen1.name();
}
}
運(yùn)行結(jié)果:

這個(gè)時(shí)候發(fā)現(xiàn)客戶(hù)端不在和一個(gè)具體的子類(lèi)耦合在一起了,就算以后增加了新的子類(lèi),那么也只需要修改Factory類(lèi)即可。
小結(jié):
- 以后如果是自己編寫(xiě)的接口如果想要取得接口的 實(shí)例化對(duì)象,第一反應(yīng)寫(xiě)工廠(chǎng)類(lèi)
- 簡(jiǎn)單工廠(chǎng)和工廠(chǎng)方法模式的不同在于前者生成產(chǎn)生產(chǎn)品的行為封裝在一個(gè)方法中,根據(jù)參數(shù)的類(lèi)型進(jìn)行實(shí)例化,同時(shí)不存在抽象接口。而后者則增加了抽象工廠(chǎng),通過(guò)實(shí)現(xiàn)不同的工廠(chǎng)方法來(lái)創(chuàng)建不同的產(chǎn)品,一個(gè)方法通常對(duì)應(yīng)一個(gè)產(chǎn)品,這種方式相較于前者擴(kuò)展性更高,在需求增加時(shí)完全符合開(kāi)閉原則和依賴(lài)倒置原則
使用場(chǎng)景:
消費(fèi)者不關(guān)心它所要?jiǎng)?chuàng)建對(duì)象的類(lèi)(產(chǎn)品類(lèi))的時(shí)候。
消費(fèi)者知道它所要?jiǎng)?chuàng)建對(duì)象的類(lèi)(產(chǎn)品類(lèi)),但不關(guān)心如何創(chuàng)建的時(shí)候。
例如:hibernate里通過(guò)sessionFactory創(chuàng)建session、通過(guò)代理方式生成ws客戶(hù)端時(shí),通過(guò)工廠(chǎng)構(gòu)建報(bào)文中格式化數(shù)據(jù)的對(duì)象。
3、抽象工廠(chǎng)模式
定義:為創(chuàng)建一組相關(guān)或相互依賴(lài)的對(duì)象提供一個(gè)接口,而且無(wú)需指定他們的具體類(lèi)。
抽象工廠(chǎng)模式與工廠(chǎng)方法模式的區(qū)別
抽象工廠(chǎng)模式是工廠(chǎng)方法模式的升級(jí)版本,他用來(lái)創(chuàng)建一組相關(guān)或者相互依賴(lài)的對(duì)象。他與工廠(chǎng)方法模式的區(qū)別就在于,工廠(chǎng)方法模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu);而抽象工廠(chǎng)模式則是針對(duì)的多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)。在編程中,通常一個(gè)產(chǎn)品結(jié)構(gòu),表現(xiàn)為一個(gè)接口或者抽象類(lèi),也就是說(shuō),工廠(chǎng)方法模式提供的所有產(chǎn)品都是衍生自同一個(gè)接口或抽象類(lèi),而抽象工廠(chǎng)模式所提供的產(chǎn)品則是衍生自不同的接口或抽象類(lèi)。
在抽象工廠(chǎng)模式中,有一個(gè)產(chǎn)品族的概念:所謂的產(chǎn)品族,是指位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中功能相關(guān)聯(lián)的產(chǎn)品組成的家族。抽象工廠(chǎng)模式所提供的一系列產(chǎn)品就組成一個(gè)產(chǎn)品族;而工廠(chǎng)方法提供的一系列產(chǎn)品稱(chēng)為一個(gè)等級(jí)結(jié)構(gòu)。.
如果工廠(chǎng)的產(chǎn)品全部屬于同一個(gè)等級(jí)結(jié)構(gòu),則屬于工廠(chǎng)方法模式;如果工廠(chǎng)的產(chǎn)品來(lái)自多個(gè)等級(jí)結(jié)構(gòu),則屬于抽象工廠(chǎng)模式。
UML圖:

源代碼:
Factory.java(抽象工廠(chǎng))
public interface Factory {
PhoneProject projectPhone();
LaptopProject projectLaptop();
}
HuaWeiFactory.java(華為具體工廠(chǎng))
public class HuaWeiFactory implements Factory{
@Override
public PhoneProject projectPhone() {
// TODO Auto-generated method stub
return new HuaWeiPhone();
}
@Override
public LaptopProject projectLaptop() {
// TODO Auto-generated method stub
return new HuaWeiLaptop();
}
}
XiaomiFactory.java(小米具體工廠(chǎng))
public class XiaomiFactory implements Factory{
@Override
public PhoneProject projectPhone() {
// TODO Auto-generated method stub
return new XiaomiPhone();
}
@Override
public LaptopProject projectLaptop() {
// TODO Auto-generated method stub
return new XiaomiLaptop();
}
}
LaptopProject.java(筆記本產(chǎn)品)
public interface LaptopProject {
void getId();
void printInfo();
}
HuaWeiLaptop.java(華為筆記本)
public class HuaWeiLaptop implements LaptopProject{
@Override
public void getId() {
// TODO Auto-generated method stub
System.out.println("編號(hào)"+123);
}
@Override
public void printInfo() {
// TODO Auto-generated method stub
System.out.println("生產(chǎn)了華為電腦");
}
}
XiaomiLaptop.java(小米筆記本)
public class XiaomiLaptop implements LaptopProject{
@Override
public void getId() {
// TODO Auto-generated method stub
System.out.println("編號(hào)"+213);
}
@Override
public void printInfo() {
// TODO Auto-generated method stub
System.out.println("生產(chǎn)小米電腦");
}
}
PhoneProject.java(手機(jī)產(chǎn)品)
public interface PhoneProject {
void getId();
void printInfo();
}
HuaWeiPhone.java(華為手機(jī))
public class HuaWeiPhone implements PhoneProject{
@Override
public void getId() {
// TODO Auto-generated method stub
System.out.println("編號(hào):"+123412);
}
@Override
public void printInfo() {
// TODO Auto-generated method stub
System.out.println("生產(chǎn)華為手機(jī)");
}
}
XiaomiPhone.java(小米手機(jī))
public class XiaomiPhone implements PhoneProject{
@Override
public void getId() {
// TODO Auto-generated method stub
System.out.println("編號(hào):"+123412);
}
@Override
public void printInfo() {
// TODO Auto-generated method stub
System.out.println("生產(chǎn)了小米手機(jī)??!");
}
}
測(cè)試類(lèi):
public class Client {
public static void main(String[] args) {
PhoneProject huawei = new HuaWeiFactory().projectPhone();
huawei.printInfo();
huawei.getId();
PhoneProject xiaomi = new XiaomiFactory().projectPhone();
xiaomi.printInfo();
LaptopProject huawei1 = new HuaWeiFactory().projectLaptop();
huawei1.printInfo();
}
}
運(yùn)行結(jié)果:

總結(jié):
抽象工廠(chǎng)模式是工廠(chǎng)方法模式的升級(jí)版,后者面向單個(gè)產(chǎn)品,而前者面向的的是一個(gè)產(chǎn)品族。根據(jù)官方定義:為創(chuàng)建一組相關(guān)/互相依賴(lài)的對(duì)象提供一個(gè)接口而無(wú)需指定它們的具體類(lèi)。
比如一個(gè)汽車(chē)工廠(chǎng)要生成騎車(chē),而每種汽車(chē)都有車(chē)門(mén)、車(chē)輪胎等一系列產(chǎn)品,這意味著每增加一款汽車(chē)就需要增加一個(gè)新的工廠(chǎng)來(lái)提供新產(chǎn)品的實(shí)現(xiàn)。這時(shí)候就可以使用抽象工廠(chǎng)模式來(lái)進(jìn)行設(shè)計(jì)。抽象工廠(chǎng)模式適用于一系列產(chǎn)品族。
優(yōu)點(diǎn): 抽象廠(chǎng)模式將產(chǎn)品族的依賴(lài)與約束關(guān)系放到抽象工廠(chǎng)中,便于管理。職責(zé)解耦,用戶(hù)不需要關(guān)心一堆自己不關(guān)心的細(xì)節(jié),由抽象廠(chǎng)來(lái)負(fù)責(zé)組件的創(chuàng)建切換產(chǎn)品族容易,只需要增加一個(gè)具體工廠(chǎng)實(shí)現(xiàn),客戶(hù)端選擇另-個(gè)套餐就可以了 缺點(diǎn): 抽象工廠(chǎng)模式類(lèi)增加的速度很快,有一個(gè)產(chǎn)品族就需要增加一一個(gè)具體工廠(chǎng)實(shí)現(xiàn),比較繁瑣產(chǎn)品族難以擴(kuò)展產(chǎn)品。當(dāng)產(chǎn)品族中增加一個(gè)產(chǎn)品時(shí),抽象工廠(chǎng)接口中需要增加一個(gè)函數(shù),對(duì)應(yīng)的所有具體工廠(chǎng)實(shí)現(xiàn)都需要修改,修改放大嚴(yán)重。抽象廠(chǎng)并未完全屏蔽創(chuàng)建細(xì)節(jié),給出的都是組件。對(duì)于這種情況可以結(jié)合工廠(chǎng)模式或簡(jiǎn)單工廠(chǎng)模式-起使用。 使用場(chǎng)景:
大家應(yīng)該已經(jīng)發(fā)現(xiàn)了,其實(shí)抽象工廠(chǎng)模式如果只有一個(gè)組件的話(huà),其實(shí)是退化到工廠(chǎng)方法模式,也就是沒(méi)有了產(chǎn)品族的概念,只剩一一個(gè)產(chǎn)品了,因此簡(jiǎn)單工廠(chǎng),廠(chǎng)方法,抽象工廠(chǎng)這三者之間是有內(nèi)在聯(lián)系的,區(qū)別只產(chǎn)品的復(fù)雜度。抽象工廠(chǎng)的本質(zhì)是選擇產(chǎn)品族,因此大家可以根據(jù)這個(gè)特征來(lái)識(shí)別是否可以應(yīng)用抽象廠(chǎng)。
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
mybatis中實(shí)現(xiàn)枚舉自動(dòng)轉(zhuǎn)換方法詳解
在使用mybatis的時(shí)候經(jīng)常會(huì)遇到枚舉類(lèi)型的轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于mybatis中實(shí)現(xiàn)枚舉自動(dòng)轉(zhuǎn)換的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-08-08
基于JDBC訪(fǎng)問(wèn)MySql公共方法實(shí)例解析
這篇文章主要介紹了基于JDBC訪(fǎng)問(wèn)MySql公共方法實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
2020最新eclipse安裝過(guò)程及細(xì)節(jié)
這篇文章主要介紹了2020最新eclipse安裝過(guò)程及細(xì)節(jié),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Spring Security實(shí)現(xiàn)身份認(rèn)證和授權(quán)的示例代碼
在 Spring Boot 應(yīng)用中使用 Spring Security 可以非常方便地實(shí)現(xiàn)用戶(hù)身份認(rèn)證和授權(quán),本文主要介紹了Spring Security實(shí)現(xiàn)身份認(rèn)證和授權(quán)的示例代碼,感興趣的可以了解一下2023-06-06
SpringCloud?客戶(hù)端Ribbon負(fù)載均衡的實(shí)現(xiàn)方法
Ribbon 是 Netflix 提供的一個(gè)基于 Http 和 TCP 的客戶(hù)端負(fù)載均衡工具,且已集成在 Eureka 依賴(lài)中,這篇文章主要介紹了SpringCloud?客戶(hù)端Ribbon負(fù)載均衡的實(shí)現(xiàn)方法,需要的朋友可以參考下2022-06-06
Java Socket編程實(shí)例(三)- TCP服務(wù)端線(xiàn)程池
這篇文章主要講解Java Socket編程中TCP服務(wù)端線(xiàn)程池的實(shí)例,希望能給大家做一個(gè)參考。2016-06-06
SpringBoot使用Nacos動(dòng)態(tài)配置數(shù)據(jù)源的方法
這篇文章主要介紹了SpringBoot使用Nacos動(dòng)態(tài)配置數(shù)據(jù)源的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
SpringBoot + SpringSecurity 環(huán)境搭建的步驟
這篇文章主要介紹了SpringBoot + SpringSecurity 環(huán)境搭建的步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

