设计模式-工厂方法

工厂方法模式

简单工厂的不足

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

在工厂方法模式中,存在4个角色:

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

工厂方法模式下的多日志工厂

Log(抽象产品)

抽象Log声明了一个记录日志的方法

copy
package com.example.fxfactory.model; import java.io.IOException; public abstract class Log { public abstract void doLog() throws IOException; }

ConsoleLog(具体产品)

Log的具体类,控制台日志,它将doLog重写为在控制台打印日志信息

copy
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文件中去

copy
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(抽象工厂)

抽象的日志工厂,声明了一个创建日志的方法,返回类型为抽象的日志

copy
package com.example.fxfactory.factory; import com.example.fxfactory.model.Log; public abstract class LogFactory { public abstract Log createLog(); }

ConsoleLogFactory(具体工厂)

控制台日志工厂,重写创建日志方法,返回一个控制台日志实例

copy
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(具体工厂)

文件日志工厂,重写创建日志方法,返回一个文件日志实例

copy
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

copy
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,新增一个切换到具体工厂的方法,接收具体工厂名,将自己变为指定的具体工厂

copy
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

copy
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方法

总结

工厂方法的优点

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

工厂方法的缺点

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

posted @   Evanpatchouli  阅读(69)  评论(0编辑  收藏  举报
相关博文:
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起