您的位置:首页 > 编程语言 > Java开发

设计模式初探之工厂方法模式

2017-12-03 12:25 204 查看
 这篇博客更新距离上一篇时间格得有点长,一方面是最近工作较忙,另一方面得检讨下是不是又变懒了。

一、概述简单工厂模式的缺点,工厂方法模式的改进

        这一篇将带来的是工厂方法模式,我的第一篇设计模式的博客写的就是简单工厂模式:简单工厂模式,工厂模式可以说是简单工厂模式的一个升级版,克服了简单工厂模式存在的一些问题。所以两者都是非常相似的,都是通过工厂类去创建对象,从而对客户端隐藏对象创建的细节。首先先看看简单工厂模式的缺点。

         1、简单工厂模式中工厂类用于创建所有的产品,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性。各种创建产品的代码混在工厂类中。容易造成代码的混乱。

         2、简单工厂模式违背了"开源-封闭原则",当加入新的产品时,除了去创建新的产品之外,还得去修改工厂类。当然,在简单工厂模式的那篇文章中,通过反射可以在新增产品时不用修改工厂类,但这种实现是有局限的,它的使用条件在于各个产品创建都不需要做些独特处理,当每个产品的创建都需要做不同的初始化时,这种方式就不能使用了。

         3、工厂类过于庞大,包含了大量的if…else…代码,导致维护和测试难度增大

基于以上简单工厂模式的缺点,工厂方法模式在简单工厂模式进行改进。

二、工厂方法模式的类图:



看了类图,是不是感觉很简单,是的,工厂方法模式是比较简单,容易理解的一种模式。其中有几个元素。

1、抽象产品类,对产品的抽象,定义产品的一些共性。2、具体产品,具体产品的实现。3、抽象工厂类,定义具体工厂类该实现的方法。4、具体工厂类,实现创建产品的方法。

相比静态工厂模式,工厂模式为每个产品添加自己的工厂类。这样每个产品的创建都在自己的工厂类内实现,这样就分离了各个产品创建混杂在一起,从而更容易测试,也减低了静态工厂模式下,单一工厂类的职责和复杂度。同时,每创建新产品,只需新增产品及产品对应的工厂类,而无需修改其他工厂类,这就符合了“开闭原则”。使得代码的结构,各产品更清晰,更适合阅读。

三、例子。

我们在开发中免不了要打印日志,但日志的打印地点有许多不同的要求,比如说,我们在开发中,经常希望将日志打印在控制台,方便开发工程中的调试,而在上线后,我们希望通过文件来记录日志。甚至还有需要将日志输出成字节流的形式保存到其他地方的需求。不同的打印需要不同的类来实现。实现打印在不同地点的类就是我们这里工厂模式的产品,我们还需创建他们的工厂类,实现打印日志对象的创建。

日志抽象类。

package product;

public interface ILog {
void writeLog();
}


将日志打印到文件,具体实现类。

package product;

public class FileLog implements ILog {

private String filePath;

public FileLog(String filePath) {
super();
this.filePath = filePath;
}

@Override
public void writeLog() {
// TODO Auto-generated method stub
System.out.println("将日志打印到文件:"+filePath);
}

}


将日志打印到控制台,具体实现类。

package product;

import java.util.Date;

public class ConsoleLog implements ILog {

private Date logDate;

@Override
public void writeLog() {
// TODO Auto-generated method stub
logDate = new Date();
System.out.println("日志打印到控制台,时间:"+logDate);
}

}


有了具体的产品,这是我们就需要创建他们的工厂类。

抽象工厂类:

package factory;

import product.ILog;

public interface IFactory {

ILog createProduct();
}
打印日志到文件的具体工厂类。

package factory;

import product.FileLog;
import product.ILog;

public class FileLogFactory implements IFactory {

@Override
public ILog createProduct() {
// TODO Auto-generated method stub
ILog log = new FileLog("c:/log/test.log");
return log;
}

}


打印日志到控制台具体工厂类:

package factory;

import product.ConsoleLog;
import product.ILog;

public class ConsoleLogFactory implements IFactory {

@Override
public ILog createProduct() {
// TODO Auto-generated method stub
return new ConsoleLog();
}

}


这样我们就实现就工厂方法模式。具体的测试类如下。

import factory.ConsoleLogFactory;
import factory.FileLogFactory;
import factory.IFactory;
import product.ConsoleLog;
import product.ILog;

public class Test {

public static void main(String[] args) {
// TODO Auto-generated method stub
IFactory factory = new FileLogFactory();
ILog fileLog = factory.createProduct();
fileLog.writeLog();

factory = new ConsoleLogFactory();
ILog consoleLog = factory.createProduct();
consoleLog.writeLog();
}

}

这时如果我们想增加一个实现将日志输出成字节流是,我们只需新增日志的打印字节流实现,还有新增他的工厂类,无需修改其他任何的代码。

package product;

public class StreamLog implements ILog {

@Override
public void writeLog() {
// TODO Auto-generated method stub
System.out.println("将日志输出成字节流的形式");
}

}
package factory;

import product.ILog;
import product.StreamLog;

public class StreamLogFactory implements IFactory{

@Override
public ILog createProduct() {
// TODO Auto-generated method stub
return new StreamLog();
}

}


这样,我们的简例就实现了工厂方法模式,是不是很简单啊,不知道你理解了么。

四、总结

接下来我们从优点还有缺陷中总结一下工厂方法模式。

优点

1、工厂方法模式同简单工厂方法模式一样,实现了对客户端隐藏具体对象创建的具体细节,客户端不需要知道对象创建的过程,只需要知道通过工厂类即可创建具体的产品。

2、工厂类完全符合开源封闭原则,各产品直接没有耦合,新增产品方便,而且易于测试。

缺点

1、每新增一个产品,就得对应着新增一个工厂类,这样就会造成需新建的类比较多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息