文章插图
前言工厂设计模式可能是最常用的设计模式之一,我想大家在自己的项目中都用到过 。可能你会不屑一顾,但这篇文章不仅仅是关于工厂模式的基本知识,更是讨论如何在运行时动态选择不同的方法进行执行,你们可以看看是不是和你们项目中用的一样?
小菜鸟的问题直接上例子说明,设计一个日志记录的功能,但是支持记录到不同的地方,例如:
- 内存中
- 磁盘上的文件
- 数据库
- 百度网盘等远程存储服务
- 小菜鸟创建了一个Logger类
class Logger {public void log(String message, String loggerMedium) {}}
- 小菜鸟想都不想,直接一通if else 。
class Logger {public void log(String message, String loggerMedium) {if (loggerMedium.equals("MEMORY")) {logInMemory(message);} else if (loggerMedium.equals("FILE")) {logOnFile(message);} else if (loggerMedium.equals("DB")) {logToDB(message);} else if (loggerMedium.equals("REMOTE_SERVICE")) {logToRemote(message);}}private void logInMemory(String message) {// Implementation}private void logOnFile(String message) {// Implementation}private void logToDB(String message) {// Implementation}private void logToRemote(String message) {// Implementation}}
现在突然说要增加一种存储介质FLASH_DRIVE,就要改了这个类?不拍改错吗?也不符合“开闭原则”,而且随着存储介质变多,类也会变的很大,小菜鸟懵逼了,不知道怎么办?有没有更好的方法呢?这时候小菜鸟去找你帮忙,你一顿操作,改成了下面这样:
class InMemoryLog {public void logToMemory(String message) {// Implementation}}class FileLog {public void logToFile(String message) {//Implementation}}class DBLog {public void logToDB(String message) {// Implementation}}class RemoteServiceLog {public void logToService(String message) {// Implementation}}class Logger {private InMemoryLog mLog;private FileLog fLog;private DBLog dbLog;private RemoteServiceLog sLog;public Logger() {mLog = new InMemoryLog();fLog = new FileLog();dbLog = new DBLog();sLog = new RemoteServiceLog();}public void log(String message, String loggerMedium) {if (loggerMedium.equals("MEMORY")) {mLog.logToMemory(message);} else if (loggerMedium.equals("FILE")) {fLog.logToFile(message);} else if (loggerMedium.equals("DB")) {dbLog.logToDB(message);} else if (loggerMedium.equals("REMOTE_SERVICE")) {sLog.logToService(message);}}}
在这个实现中,你已经将单独的代码分离到它们对应的文件中,但是Logger类与存储介质的具体实现紧密耦合,如FileLog、DBLog等 。随着存储介质的增加,类中将引入更多的实例Logger 。还有什么更好的办法吗?你想了想,上面的实现都是直接写具体的实现类,是面向实现编程,更合理的做法是面向接口编程,接口意味着协议,契约,是一种更加稳定的方式 。
- 定义一个日志操作的接口
public interface LoggingOperation {void log(String message);}
- 实现这个接口
class InMemoryLog implements LoggingOperation {public void log(String message) {// Implementation}}class FileLog implements LoggingOperation {public void log(String message) {//Implementation}}class DBLog implements LoggingOperation {public void log(String message) {// Implementation}}class RemoteServiceLog implements LoggingOperation {public void log(String message) {// Implementation}}
- 你定义了一个类,据传递的参数,在运行时动态选择具体实现,这就是所谓的工厂类,不过是基础版 。
class LoggerFactory {public static LoggingOperation getInstance(String loggerMedium) {LoggingOperation op = null;switch (loggerMedium) {case "MEMORY":op = new InMemoryLog();break;case "FILE":op = new FileLog();break;case "DB":op = new DBLog();break;case "REMOTE_SERVICE":op = new RemoteServiceLog();break;}return op;}}
- 现在你的 Logger类的实现就是下面这个样子了 。
class Logger {public void log(String message, String loggerMedium) {LoggingOperation instance = LoggerFactory.getInstance(loggerMedium);instance.log(message);}}
这里的代码变得非常统一,创建实际存储实例的责任已经转移到LoggerFactory,各个存储类只实现它们如何将消息记录到它们的特定介质,最后该类Logger只关心通过LoggerFactory将实际的日志记录委托给具体的实现 。这样,代码就很松耦合了 。你想要添加一个新的存储介质,例如FLASH_DRIVE,只需创建一个实现LoggingOperation接口的新类并将其注册到LoggerFactory中就好了 。这就是工厂模式可以帮助您动态选择实现的方式 。
推荐阅读
- 兼容模式什么意思 兼容模式
- 新商业模式创新设计?新零售时代的新商业模式是什么意思?
- h1z1生存模式还能玩吗?《H1Z1》配置要求是什么?
- 林肯suv车型价格多少 林肯mkx
- 工厂工场区别?工厂与工场有何区别?
- 硬件检测模式怎么进去 硬件检测
- 海盗船项链 海盗船首饰
- 工人|外资工厂招聘工人抢着去,国内工厂反而招工难!两者到底有何区别
- Android的四种启动模式
- TikTok商业模式揭秘:兴趣电商的商机之路,从“人找货”到“货找人”的新体验