找回密码
 立即注册
首页 业界区 业界 设计模式-工厂方法

设计模式-工厂方法

蒙飘 2025-6-6 09:47:47
工厂方法模式

简单工厂的不足

上节的简单工厂,需要拓展时比如修改工厂类,违背了设计模式的开闭原则
简单工厂类直接生成各个子类产品,而工厂方法则有一个抽象工厂类,声明了创建产品的工厂方法,而各个不同的子类产品交由各个不同的具体工厂去完成创建,拓展时,只需要新建一个具体工厂即可,具有更好的灵活性和拓展性
在工厂方法模式中,存在4个角色:

  • 抽象产品
  • 具体产品
  • 抽象工厂
    声明了创建产品的抽象方法,返回抽象产品,由具体工厂去实现创建具体产品的方法
  • 具体工厂
    实现创建产品的抽象方法,创建并返回某一种具体产品
工厂方法模式下的多日志工厂

Log(抽象产品)

抽象Log声明了一个记录日志的方法
  1. package com.example.fxfactory.model;
  2. import java.io.IOException;
  3. public abstract class Log {
  4.     public abstract void doLog() throws IOException;
  5. }
复制代码
ConsoleLog(具体产品)

Log的具体类,控制台日志,它将doLog重写为在控制台打印日志信息
  1. package com.example.fxfactory.model;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  4. public class ConsoleLog extends Log{
  5.     @Override
  6.     public void doLog() {
  7.         Date date = new Date();
  8.         SimpleDateFormat pattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  9.         String str = pattern.format(date) + "  console log";
  10.         System.out.println(str);
  11.     }
  12. }
复制代码
FileLog(具体产品)

Log的另一个具体类,文件日志,它将doLog重写为记录日志到filelog.txt文件中去
  1. package com.example.fxfactory.model;
  2. import java.io.File;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Date;
  7. public class FileLog extends Log {
  8.     @Override
  9.     public void doLog() throws IOException {
  10.         File dir = new File("./log");
  11.         if (!dir.exists()) {
  12.             dir.mkdirs();
  13.         }
  14.         File checkFile = new File("./log","filelog.txt");
  15.         FileWriter writer = null;
  16.         try {
  17.             if (!checkFile.exists()) {
  18.                 checkFile.createNewFile();
  19.             }
  20.             writer = new FileWriter(checkFile, true);
  21.             Date date = new Date();
  22.             SimpleDateFormat pattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  23.             String str = pattern.format(date) + "  file log";
  24.             writer.append(str);
  25.             writer.flush();
  26.         } catch (IOException e) {
  27.             e.printStackTrace();
  28.         } finally {
  29.             if (null != writer)
  30.                 writer.close();
  31.         }
  32.     }
  33. }
复制代码
LogFactory(抽象工厂)

抽象的日志工厂,声明了一个创建日志的方法,返回类型为抽象的日志
  1. package com.example.fxfactory.factory;
  2. import com.example.fxfactory.model.Log;
  3. public abstract class LogFactory {
  4.     public abstract Log createLog();
  5. }
复制代码
ConsoleLogFactory(具体工厂)

控制台日志工厂,重写创建日志方法,返回一个控制台日志实例
  1. package com.example.fxfactory.factory;
  2. import com.example.fxfactory.model.ConsoleLog;
  3. import com.example.fxfactory.model.Log;
  4. public class ConsoleLogFactory extends LogFactory {
  5.     @Override
  6.     public Log createLog() {
  7.         return new ConsoleLog();
  8.     }
  9. }
复制代码
FileLogFactory(具体工厂)

文件日志工厂,重写创建日志方法,返回一个文件日志实例
  1. package com.example.fxfactory.factory;
  2. import com.example.fxfactory.model.FileLog;
  3. import com.example.fxfactory.model.Log;
  4. public class FileLogFactory extends LogFactory {
  5.     @Override
  6.     public Log createLog() {
  7.         return new FileLog();
  8.     }
  9. }
复制代码
测试

Main.java
  1. package com.example.fxfactory;
  2. import com.example.fxfactory.factory.ConsoleLogFactory;
  3. import com.example.fxfactory.factory.FileLogFactory;
  4. import com.example.fxfactory.factory.LogFactory;
  5. import com.example.fxfactory.model.Log;
  6. import java.io.IOException;
  7. public class Main {
  8.     public static void main(String[] args) throws IOException {
  9.         LogFactory logFactory = new ConsoleLogFactory();
  10.         Log consoleLog = logFactory.createLog();
  11.         consoleLog.doLog();
  12.         logFactory = new FileLogFactory();
  13.         Log fileLog = logFactory.createLog();
  14.         fileLog.doLog();
  15.     }
  16. }
复制代码
看起来,我们似乎并不需要LogFactory,直接创建2个不同的具体Factory不也行吗?那我们尝试换一种写法:
空工厂

抽象工厂换为一个空工厂,createLog方法返回null,新增一个切换到具体工厂的方法,接收具体工厂名,将自己变为指定的具体工厂
  1. package com.example.fxfactory.factory;
  2. import com.example.fxfactory.model.Log;
  3. public class LogFactory {
  4.     public LogFactory siwtch(String logType){
  5.         switch (logType){
  6.             case "console":{
  7.                 return new ConsoleLogFactory();
  8.             }
  9.             case "file":{
  10.                 return new FileLogFactory();
  11.             }
  12.             default:{
  13.                 return this;
  14.             }
  15.         }
  16.     }
  17.     public Log createLog(){
  18.         return null;
  19.     }
  20. }
复制代码
测试

Main.java
  1. LogFactory logFactory = new LogFactory();
  2.         logFactory = logFactory.siwtch("console");
  3.         Log consoleLog = logFactory.createLog();
  4.         consoleLog.doLog();
  5.         logFactory = logFactory.siwtch("file");
  6.         Log fileLog = logFactory.createLog();
  7.         fileLog.doLog();
复制代码
现在我们不需要知道具体工厂类了,只需要知道用于指定它们的名字就行。不过要拓展新的具体工厂,还需要维护空工厂的switch方法
总结

工厂方法的优点

★ 客户无须关心生成细节和具体产品的类名
★ 良好的多态性:创建细节完全封装在具体工厂内
易拓展性:无须修改抽象工厂,新增基于抽象工厂的新具体工厂类即可
工厂方法的缺点

★ 新产品和新具体工厂成对,一定程度上增加了系统复杂性
★ 双重抽象(产品和工厂),一定程度上增加了系统的抽象性和理解难度

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册