工廠方法模式
簡單工廠的不足
上節的簡單工廠,需要拓展時比如修改工廠類,違背了設計模式的開閉原則
簡單工廠類直接生成各個子類產品,而工廠方法則有一個抽象工廠類,宣告了創建產品的工廠方法,而各個不同的子類產品交由各個不同的具體工廠去完成創建,拓展時,只需要新建一個具體工廠即可,具有更好的靈活性和拓展性
在工廠方法模式中,存在4個角色:
- 抽象產品
- 具體產品
- 抽象工廠
宣告了創建產品的抽象方法,回傳抽象產品,由具體工廠去實作創建具體產品的方法 - 具體工廠
實作創建產品的抽象方法,創建并回傳某一種具體產品
工廠方法模式下的多日志工廠
Log(抽象產品)
抽象Log宣告了一個記錄日志的方法
package com.example.fxfactory.model;
import java.io.IOException;
public abstract class Log {
public abstract void doLog() throws IOException;
}
ConsoleLog(具體產品)
Log的具體類,控制臺日志,它將doLog重寫為在控制臺列印日志資訊
package com.example.fxfactory.model;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ConsoleLog extends Log{
@Override
public void doLog() {
Date date = new Date();
SimpleDateFormat pattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = pattern.format(date) + " console log";
System.out.println(str);
}
}
FileLog(具體產品)
Log的另一個具體類,檔案日志,它將doLog重寫為記錄日志到filelog.txt檔案中去
package com.example.fxfactory.model;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileLog extends Log {
@Override
public void doLog() throws IOException {
File dir = new File("./log");
if (!dir.exists()) {
dir.mkdirs();
}
File checkFile = new File("./log","filelog.txt");
FileWriter writer = null;
try {
if (!checkFile.exists()) {
checkFile.createNewFile();
}
writer = new FileWriter(checkFile, true);
Date date = new Date();
SimpleDateFormat pattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = pattern.format(date) + " file log";
writer.append(str);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != writer)
writer.close();
}
}
}
LogFactory(抽象工廠)
抽象的日志工廠,宣告了一個創建日志的方法,回傳型別為抽象的日志
package com.example.fxfactory.factory;
import com.example.fxfactory.model.Log;
public abstract class LogFactory {
public abstract Log createLog();
}
ConsoleLogFactory(具體工廠)
控制臺日志工廠,重寫創建日志方法,回傳一個控制臺日志實體
package com.example.fxfactory.factory;
import com.example.fxfactory.model.ConsoleLog;
import com.example.fxfactory.model.Log;
public class ConsoleLogFactory extends LogFactory {
@Override
public Log createLog() {
return new ConsoleLog();
}
}
FileLogFactory(具體工廠)
檔案日志工廠,重寫創建日志方法,回傳一個檔案日志實體
package com.example.fxfactory.factory;
import com.example.fxfactory.model.FileLog;
import com.example.fxfactory.model.Log;
public class FileLogFactory extends LogFactory {
@Override
public Log createLog() {
return new FileLog();
}
}
測驗
Main.java
package com.example.fxfactory;
import com.example.fxfactory.factory.ConsoleLogFactory;
import com.example.fxfactory.factory.FileLogFactory;
import com.example.fxfactory.factory.LogFactory;
import com.example.fxfactory.model.Log;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
LogFactory logFactory = new ConsoleLogFactory();
Log consoleLog = logFactory.createLog();
consoleLog.doLog();
logFactory = new FileLogFactory();
Log fileLog = logFactory.createLog();
fileLog.doLog();
}
}
看起來,我們似乎并不需要LogFactory,直接創建2個不同的具體Factory不也行嗎?那我們嘗試換一種寫法:
空工廠
抽象工廠換為一個空工廠,createLog方法回傳null,新增一個切換到具體工廠的方法,接收具體工廠名,將自己變為指定的具體工廠
package com.example.fxfactory.factory;
import com.example.fxfactory.model.Log;
public class LogFactory {
public LogFactory siwtch(String logType){
switch (logType){
case "console":{
return new ConsoleLogFactory();
}
case "file":{
return new FileLogFactory();
}
default:{
return this;
}
}
}
public Log createLog(){
return null;
}
}
測驗
Main.java
LogFactory logFactory = new LogFactory();
logFactory = logFactory.siwtch("console");
Log consoleLog = logFactory.createLog();
consoleLog.doLog();
logFactory = logFactory.siwtch("file");
Log fileLog = logFactory.createLog();
fileLog.doLog();
現在我們不需要知道具體工廠類了,只需要知道用于指定它們的名字就行,不過要拓展新的具體工廠,還需要維護空工廠的switch方法
總結
工廠方法的優點
★ 客戶無須關心生成細節和具體產品的類名
★ 良好的多型性:創建細節完全封裝在具體工廠內
★ 易拓展性:無須修改抽象工廠,新增基于抽象工廠的新具體工廠類即可
工廠方法的缺點
★ 新產品和新具體工廠成對,一定程度上增加了系統復雜性
★ 雙重抽象(產品和工廠),一定程度上增加了系統的抽象性和理解難度
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/551522.html
標籤:設計模式
下一篇:返回列表
