设计模式(3)——工厂方法模式

在简单工厂模式中,通过判断传入的参数来决定创建哪一个对象实例,而如果需要在工厂中新增产品或删除产品,则只能通过修改工厂类的源代码进行实现,这就违反了开闭原则。

而工厂方法模式可以在新增产品的时候无需修改原有代码

1. 引出问题

需求:设计一个日志记录器,可以通过多种途径(文件记录、数据库记录)保存系统的运行日志,用户可以通过修改配置文件的方式更换日志记录方式。同时,该日志记录器需要进行复杂的初始化设置。

由需求可知,该程序的设计具有两个要点:

  1. 需要封装程序的初始化过程,由于初始化较复杂,故代码量可能较大,若写在构造函数中,会导致程序臃肿
  2. 由于用户可能更换记录方式,需要提供一种更加灵活的方式来满足用户更换或新增日志记录方式的需求

此处先以简单工厂模式进行实现

public class LoggerFactory {

    //静态工厂方法
    public static Logger createLogger(String args){

        if(args.equalsIgnoreCase("db")){
            //创建数据库,代码省略

            //创建数据库日志记录器对象
            Logger logger = new DatabaseLogger();

            //初始化数据库日志记录器,代码省略

            return logger;
        }else if(args.equalsIgnoreCase("file")){
            //创建日志文件,代码省略

            //创建文件日志记录器对象
            Logger logger = new DatabaseLogger();

            //初始化文件日志记录器,代码省略

            return logger;
        }else{
            return null;
        }

    }
}

存在的问题:

  1. 存在大量的条件判断语句,代码臃肿
  2. 对于日志记录方式的扩展不灵活,违反开闭原则

2. 工厂方法模式介绍

定义一个用于创建对象的接口,让子类决定具体将哪一个类实例化。

工厂方法模式让一个类的实例化延迟到其子类。

工厂方法模式简称工厂模式,又称虚拟构造器模式多态工厂模式

工厂方法模式中,不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂

工厂方法模式包含以下四种角色:

  1. Product(抽象产品)
  2. ConcreteProduct(具体产品):实现抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体产品和具体工厂之间具有一一对应的关系
  3. Factory(抽象工厂)
  4. ConcreteFactory(具体工厂):是抽象工厂的子类,实现了抽象工厂中定义的工厂方法,可由客户端调用,返回一个具体产品类的实例

相比于简单工厂模式,工厂方法模式最典型的特征就是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类

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

3. 以工厂方法模式重构日志记录器

抽象产品类:Logger

public interface Logger {
    void writeLog();
}

具体产品类:DatabaseLogger

public class DatabaseLogger implements Logger{
    @Override
    public void writeLog() {
        System.out.println("数据库日志记录");
    }
}

具体产品类:FileLogger

public class FileLogger implements Logger{
    @Override
    public void writeLog() {
        System.out.println("文件日志记录");
    }
}

抽象工厂类:LoggerFactory

public interface Factory {
    Logger createLogger();
}

具体工厂类:DatabaseLoggerFactory

public class DatabaseLoggerFactory implements Factory{
    @Override
    public Logger createLogger() {
        //创建数据库,代码省略

        //创建数据库日志记录器对象
        Logger logger = new DatabaseLogger();

        //初始化数据库日志记录器,代码省略

        return logger;
    }
}

具体工厂类:FileLoggerFactory

public class FileLoggerFactory implements Factory{
    @Override
    public Logger createLogger() {

        //创建文件日志记录器对象
        Logger logger = new FileLogger(); 

        //创建文件,代码省略

        return logger;
    }
}

编写客户端测试代码

public class FactoryMethodTest {
    public static void main(String[] args) {
        Factory factory;
        Logger logger;

        factory = new DatabaseLoggerFactory(); //可通过配置文件+反射的方式进行优化
        logger = factory.createLogger();

        logger.writeLog();
    }
}

测试结果如下

4. 工厂方法的隐藏

修改抽象工厂类

public interface Factory {
    void writeLog();
    Logger createLogger();
}

修改具体工厂类

public class DatabaseLoggerFactory implements Factory{
    @Override
    public void writeLog() {
        Logger logger = this.createLogger();
        logger.writeLog();
    }

    @Override
    public Logger createLogger() {
        //创建数据库,代码省略

        //创建数据库日志记录器对象
        Logger logger = new DatabaseLogger();

        //初始化数据库日志记录器,代码省略

        return logger;
    }
}

客户端

public class FactoryMethodTest {
    public static void main(String[] args) {
        Factory factory;
        Logger logger;

        factory = new DatabaseLoggerFactory();

        factory.writeLog();
    }
}

修改后的代码,在具体工厂类中添加了writeLog方法,将原有的createLogger方法整合到writeLog方法中进行调用,在客户端中只需调用新的writeLog方法即可,隐藏了原本需要由客户端调用的createLogger方法,即隐藏了工厂方法(工厂方法指的就是工厂类中创建实例的createLogger方法)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值