1.工廠方法模式
?工廠方法模式(Factory Method Pattern)是指定義一個創(chuàng)建對象的接口,但讓實現(xiàn)這個接口的類來決定實例化哪個類。工廠方法模式讓類的實例化推遲到子類中進行。在工廠方法模式中用戶只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠,無需關(guān)心創(chuàng)建細節(jié),而且加入新的產(chǎn)品時也符合開閉原則。
?工廠方法模式主要解決的是產(chǎn)品擴展問題。在簡單工廠模式中,隨著產(chǎn)品鏈的豐富,如果每個課程的創(chuàng)建邏輯有區(qū)別,則工廠的職責(zé)會變得越來越多。最后形成的臃腫結(jié)構(gòu)不便于維護。根據(jù)單一職責(zé)原則,我們將職責(zé)繼續(xù)劃分,專人干轉(zhuǎn)事。Java課程由Java工廠創(chuàng)建,Python課程由Python工廠創(chuàng)建,對工廠本身也做一個抽象。
來看代碼,首先創(chuàng)建ICourseFactory接口:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 8:57 2020/4/11
*/
public interface ICourseFactory {
ICourse create();
}
再分別創(chuàng)建子工廠,JavaCourseFactory的代碼如下:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:05 2020/4/11
*/
public class JavaCourseFactory implements ICourseFactory {
public ICourse create() {
return new JavaCourse();
}
}
PythonCourseFactory的代碼如下:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:06 2020/4/11
*/
public class PythonCourseFactory implements ICourseFactory {
public ICourse create() {
return new PythonCourse();
}
}
調(diào)用代碼:
public static void main(String[] args) {
ICourseFactory factory = new PythonCourseFactory();
ICourse course = factory.create();
course.study();
factory = new JavaCourseFactory();
course = factory.create();
course.study();
}
來看一下類結(jié)構(gòu)圖:

工廠方法模式適用于以下場景:
(1)創(chuàng)建對象需要大量重復(fù)的代碼
(2)客戶端(應(yīng)用層)不依賴于產(chǎn)品類實例如何被創(chuàng)建、如何被實現(xiàn)等細節(jié)
(3)一個類通過其子類來指定創(chuàng)建哪個對象
工廠方法模式的缺點:
(1)類的個數(shù)過多,增加了代碼編寫的復(fù)雜度
(2)增加了系統(tǒng)的抽象性和理解難度
2.抽象工廠模式
?抽象工廠模式(Abstract Factory Pattern)是指提供一個創(chuàng)建一系列相關(guān)或相互依賴的接口,無須指定他們的具體類。客戶端(應(yīng)用層)不依賴于產(chǎn)品類的實例如何被創(chuàng)建、如何被實現(xiàn)等細節(jié),強調(diào)的是一系列相關(guān)的產(chǎn)品對象(屬于同一產(chǎn)品族)一起使用創(chuàng)建對象需要大量重復(fù)的代碼。需要提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。
?如果對產(chǎn)品族和產(chǎn)品等級結(jié)構(gòu)不了解的,可以通過以下鏈接學(xué)習(xí):http://www.itdecent.cn/p/5fb1e21c4d19
?好了上代碼。還是以學(xué)習(xí)為例?,F(xiàn)在單純學(xué)習(xí)已經(jīng)無法滿足我們了,我們要養(yǎng)成良好的學(xué)習(xí)習(xí)慣,開始記筆記和做作業(yè)。在產(chǎn)品等級中增加兩個產(chǎn)品,INote筆記和IWork作業(yè)。
IWork接口:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:58 2020/4/11
*/
public interface IWork {
void write();
}
INote接口
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 9:57 2020/4/11
*/
public interface INote {
void edit();
}
然后創(chuàng)建一個抽象工廠類CourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:02 2020/4/11
*/
public interface CourseFactory {
INote createNote();
IWork createWork();
}
接下來,創(chuàng)建Java的產(chǎn)品族Java的筆記類JavaNote
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:06 2020/4/11
*/
public class JavaNote implements INote {
public void edit() {
System.out.println("編寫Java筆記");
}
}
擴展產(chǎn)品等級,新建Java的作業(yè)類JavaWork
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:14 2020/4/11
*/
public class JavaWork implements IWork {
public void write() {
System.out.println("完成Java作業(yè)");
}
}
創(chuàng)建Java產(chǎn)品族的具體工廠JavaCourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:17 2020/4/11
*/
public class JavaCourseFactory implements CourseFactory {
public INote createNote() {
return new JavaNote();
}
public IWork createWork() {
return new JavaWork();
}
}
然后創(chuàng)建Python產(chǎn)品的筆記類PythonNote:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:20 2020/4/11
*/
public class PythonNote implements INote {
public void edit() {
System.out.println("編寫Python筆記");
}
}
擴展產(chǎn)品等級,新建Python的作業(yè)類PythonWork
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:20 2020/4/11
*/
public class PythonWork implements IWork {
public void write() {
System.out.println("完成Python作業(yè)");
}
}
創(chuàng)建Python產(chǎn)品族的具體工廠PythonCourseFactory:
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:25 2020/4/11
*/
public class PythonCourseFactory implements CourseFactory {
public INote createNote() {
return new PythonNote();
}
public IWork createWork() {
return new PythonWork();
}
}
來看調(diào)用代碼
/**
* @Author: zhouzhen
* @email: zhouzhen0517@foxmail.com
* @Description
* @Date: Create in 10:28 2020/4/11
*/
public class AfpTest {
public static void main(String[] args) {
JavaCourseFactory factory = new JavaCourseFactory();
factory.createNote().edit();
factory.createWork().write();
PythonCourseFactory factory1 = new PythonCourseFactory();
factory1.createWork().write();
factory1.createNote().edit();
}
}
?上述代碼完整的描述了兩個產(chǎn)品族:Java課程和Python課程,也描述了兩個產(chǎn)品等級作業(yè)和筆記。抽象工廠模式非常完美清晰的描述了這樣一層復(fù)雜的關(guān)系。但是,如果我們要繼續(xù)擴展產(chǎn)品等級,將比如考試也加入,那我們的代碼從抽象工廠到具體工廠都要全部調(diào)整,很顯然不符合開閉原則,所以抽象工廠也是有缺點的:
(1)規(guī)定了所有可能被創(chuàng)建的產(chǎn)品集合,產(chǎn)品族中擴展新的產(chǎn)品困難,需要修改抽象工廠的接口。
(2)增加了系統(tǒng)的抽象新和理解難度。
?但在實際應(yīng)用中,產(chǎn)品等級結(jié)構(gòu)升級是很正常的一件事情,只要不升級的過于頻繁,可以根據(jù)實際情況不符合開閉原則,畢竟一切原則的本質(zhì)都只是被使用的工具。
文章參考
《Spring5核心原理》〔中〕譚勇德(Tom)