设计模式之三:工厂方法模式—多态工厂的实现

时间:2022-06-08 07:15:13
简单工厂的严重问题:
当系统中需要引进新产品时,静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,违背了开闭原则

引入工厂方法模式:
针对不同的产品提供不同的工厂
定义:
定义一个用于创建对象的接口,让子类决定将 哪一个类实例化,工厂方法迷失让一个类实例化延迟到其子类,工厂方法模式又称为工厂模式(Factory Pattern),又课称作虚拟构造器模式(VIrtual Constructor Pattern)


一、工厂方法模式概述:

引入抽象工厂角色,可以是接口,也可以是抽象类或者具体类
代码:
interface Factory{
    public Product factoryMethod();
}

class ConcreteFactory implements Factory{
    public Product factoryMethod(){
        return new COncreteFactory();
    }
}

二、完整解决方案:

interface Logger{
    public void writeLog();
}
class DatabaseLogger implements Logger{
    public void writeLog(){
        System.out.println("数据库写日志");
    }
}
class FileLogger implements Logger{
    public void writeLog(){
        System.out.println("文件写日志");
    }
}


interface LoggerFactory{
    public Logger createLogger();
}

class DatabaseLoggerFactory implements Factory{
    public Logger createLogger(){
        Logger logger =new DatabaseLogger();
        return logger();
    }
}
class FileLoggerFactory implements Factory{
    public Logger createLogger(){
        Logger logger=new FileLogger();
        return logger;
    }
}

class Client{
    public static void main(String[] args) {
        LoggerFactory factory;
        Logger logger;
        factory=new FileLoggerFactory();
        logger=factory.createLogger();
        logger.writeLog()
    }
}

三、反射与配置文件

利用反射,返回xml中指定的对象,这样修改就不用修改源码了。
<?xml version="1.0"?>
<config>
    <chartType>histogram</chartType>
</config>


import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
class XMLUtil{
    public static String getChartType(){
        try{
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
            DocumentBuilder builer=dFactory.newDocumentBuilder();
            Document doc;
            doc=builer.parse(new File("config.xml"));

            NodeList nl=doc.getElementsByTagName("className");
            Node classNode=nl.item(0).getFirstChild();
            String cName=classNode.getNodeValue();

            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
            }
        catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }    
}

Client端修改如下:
class Client{
    public static void main(String[] args) {
        LoggerFactory factory;
        Logger logger;
        factory=(LoggerFactory)XMLUtil.getBean;

        logger=factory.createLogger();
        logger.writeLog()
    } 

四、重载的工厂方法

使用工厂创建对象时,创建方法可以重载,使用args参数,obj参数,默认方式等多种参数来创建工厂
class DatabaseLoggerFactory implements Factory{
    public Logger createLogger(){
        Logger logger =new DatabaseLogger();
        return logger();
    }
    public Logger createLogger(String args){
        Logger logger =new DatabaseLogger();
        return logger();
    }

    public Logger createLogger(Object obj){
        Logger logger =new DatabaseLogger();
        return logger();
    }
}

五、工厂方法模式总结:
  1. 主要优点:
    1. 用火狐只需关心产品对应的工厂,无需关心创建细节,甚至具体产品的类的类名
    2. 多态,所有具体工厂类都具有同一个父类
    3. 加入新产品时,无需修改抽象工厂和抽象产品听的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而指套添加一个具体工厂和具体产品就可以了,扩展性好
  2. 主要缺点:
    1. 添加新产品时徐太编写新的具体产品类
    2. 为了扩展性,需要引入抽象层,增加系统的抽象性和理解难度,增加了实现的难度
  3. 适用场景:
    1. 客户端不知道其所需要的对象的类
    2. 抽象工厂类通过其子类来指定创建那个对象