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

来源:互联网 发布:怎么创造软件 编辑:程序博客网 时间:2024/06/06 01:52

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

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

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

         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;}@Overridepublic void writeLog() {// TODO Auto-generated method stubSystem.out.println("将日志打印到文件:"+filePath);}}

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

package product;import java.util.Date;public class ConsoleLog implements ILog {private Date logDate;@Overridepublic void writeLog() {// TODO Auto-generated method stublogDate = 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 {@Overridepublic ILog createProduct() {// TODO Auto-generated method stubILog log = new FileLog("c:/log/test.log");return log;}}

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

package factory;import product.ConsoleLog;import product.ILog;public class ConsoleLogFactory implements IFactory {@Overridepublic ILog createProduct() {// TODO Auto-generated method stubreturn 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 stubIFactory 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 {@Overridepublic void writeLog() {// TODO Auto-generated method stubSystem.out.println("将日志输出成字节流的形式");}}
package factory;import product.ILog;import product.StreamLog;public class StreamLogFactory implements IFactory{@Overridepublic ILog createProduct() {// TODO Auto-generated method stubreturn new StreamLog();}}

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

四、总结

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

优点

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

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

缺点

1、每新增一个产品,就得对应着新增一个工厂类,这样就会造成需新建的类比较多。










原创粉丝点击