设计模式之工厂方法模式(附实例代码下载)

工厂方法模式继承了简单工厂模式的优点,还弥补了简单工厂模式的缺陷

关于简单工厂模式请戳这里!

工厂方法模式的定义:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化,工厂方法模式让一个类的实例化延迟到其子类

简而言之就是工厂方法模式有多个子工厂,每个子工厂负责一个产品的生产,这些子工厂都有一个父类:抽象工厂

工厂方法模式包括四个角色:

1)抽象产品

2)具体产品

3)抽象工厂

4)具体工厂

不同的具体工厂可以创建不同的具体产品,当然,在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库,创建文件等

可以通过配置文件来储存具体工厂类的类名,再通过反射机制创建具体的工厂对象,这样在更新的具体工厂时无需修改源码,系统扩展更加方便

实例如下:

实例说明:模拟建设一个日志记录器,包括数据库日志记录器,文件日志记录器

1.日志记录器接口 充当抽象产品角色 

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:08:18    
 */
/*
 * 日志记录器接口 充当抽象产品角色
 */
public interface Logger {
    public void writelog();//接口定义的方法
}

2.数据库日志记录器,充当具体产品角色

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:09:54    
 */
/*
 * 数据库日志记录器,充当具体产品角色
 */
public class Databaselogger implements Logger {

    @Override
    public void writelog() {
        // TODO Auto-generated method stub
        System.out.println("数据库日志记录");
    }

}

 3.文件日志记录器,充当具体产品角色

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:11:16    
 */
/*
 * 文件日志记录器,充当具体产品角色
 */
public class FileLogger implements Logger{

    @Override
    public void writelog() {//实现接口方法
        // TODO Auto-generated method stub
        System.out.println("文件日志记录");
    }
    
}

 4.日志记录器工厂接口,充当抽象工厂角色

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:13:05    
 */
/*
 * 日志记录器工厂接口,充当抽象工厂角色
 */
public interface LoggerFactory {
    public Logger createLogger();//抽象工厂方法
}

5.数据库日志记录器工厂类 充当具体工厂角色 

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:14:41    
 */
/*
 * 数据库日志记录器工厂类 充当具体工厂角色
 */
public class DatabaseLoggerFactory implements LoggerFactory {

    @Override
    public Logger createLogger() {
        // TODO Auto-generated method stub
        //链接数据库 代码略
        
        Logger logger=new Databaselogger();//创建数据库日志记录器对象
        
        //初始化数据库日志记录器 代码略
        
        return logger;
        
    }

}

 6.文件日志记录器工厂类 充当具体工厂角色

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:16:57    
 */
/*
 * 文件日志记录器工厂类 充当具体工厂角色
 */
public class FileLoggerFactory implements LoggerFactory{

    @Override
    public Logger createLogger() {
        // TODO Auto-generated method stub
        Logger logger=new FileLogger();//创建文件日志记录器对象
        
        //创建文件 代码略
        
        return logger;
    }

}

7.客户端 

package 工厂方法模式;
/**
 *@author YB
 *@version 2019年3月16日下午3:20:06    
 */
public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        LoggerFactory loggerFactory;
        Logger logger;
        
        //loggerFactory=new FileLoggerFactory();
        loggerFactory=(LoggerFactory)XMLUtil.getBean();//引入配置文件和反射机制
        logger=loggerFactory.createLogger();
        
        logger.writelog();
        
    }

}

8.XMLUtil工具类  

package 工厂方法模式;

import java.io.*;

import javax.swing.text.Document;
import javax.xml.parsers.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.Node;
import org.w3c.dom.*;

import org.w3c.dom.NodeList;

/**
 *@author YB
 *@version 2019年3月15日下午7:08:17    
 */
public class XMLUtil {
    //该方法用于从XML配置文件中提取图表类型,并返回类型名
    public static Object getBean() {
        try {
            //创建文档对象
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
            DocumentBuilder builder=dFactory.newDocumentBuilder();
            org.w3c.dom.Document doc;
            doc=builder.parse(new File("src//工厂方法模式//config.xml"));
            
            //获取包含图表类型的文本节点
            NodeList nlList= ((org.w3c.dom.Document) doc).getElementsByTagName("className");
            org.w3c.dom.Node classNode=nlList.item(0).getFirstChild();
            String cName=classNode.getNodeValue();
            
            //通过类名生成实例对象并返回
            Class<?> c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
            
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
    }
}

 9.XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>工厂方法模式.DatabaseLoggerFactory</className>
</config>

抽象工厂方法的重载:

当然,抽象工厂的方法也是可以重载的,在抽象工厂中声明多个重载的工厂方法,在具体工厂中实现了这些工厂方法,这些工厂方法可以包含不同的业务逻辑,以满足产品对象的多样化创建需求 

抽象工厂方法的隐藏:

在具体工厂类中直接调用产品类的业务方法,这样在客户端就没有必要调用工厂方法来创建产品对象了,可以直接使用工厂对象即可调用所建产品对象中的业务方法

 

工厂方法模式是使用频率最该的设计模式之一!!!

 

优点:

1)工厂方法用来创建客户所需产品,同时还向客户隐藏了那种具体产品类将被实例化这一细节,用户只需关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品的类名

2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键,他能够让工厂自主确定创建何种产品对象,而如何创建这个对象的细节完全封装在具体工厂的内部,工厂方法模式之所以被称为多态工厂模式,正是因为所有的具体工厂都有同一抽象父类工厂

3)在系统中加入新产品时无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他具体过程和具体产品,而只要添加一个抽象工厂和抽象产品即可,这样系统的可扩展性将变得非常好,完全符合开闭原则

 缺点:

1)添加新产品时需要编写新的具体产品类还有对应的具体工厂类,系统中类的个数会增加,一定程度上增加了系统复杂度或额外开销

2)引入了抽象层,增加了系统的抽象性和理解难度

 

代码下载:链接:https://share.weiyun.com/5YH0BLz 密码:n8psgd

 

 

 

 

原文地址:https://www.cnblogs.com/yinbiao/p/10542384.html