设计模式-工厂方法模式

工厂方法模式定义了一个创建对象的接口,让子类决定实例化哪一个类。它通过延迟实例化到子类,实现了开闭原则和里氏代换原则,提高了系统扩展性。本文详细解释了模式结构,包括抽象产品、具体产品、抽象工厂和具体工厂的角色,并通过日志记录的实例展示了如何应用。
摘要由CSDN通过智能技术生成

工厂方法模式

     定义一个用来创建对象的接口,但让子类决定将那个类实例化。该模式就是让那个对象的实例化延迟到其子类进行

在工行方法模式中,工厂父类只负责定义创建产品对象的公共接口,工行子类是负责具体的产品对象创建

    工厂模式的出现弥补了简单工厂的缺陷,在简单工厂模式中,如果随着产品的增加,同时需要修改工厂创建对象的逻辑,违背了开闭原则。工厂模式利用了多态性和里氏代换原则,更好的进行系统的扩展。

开闭原则:软件实体应该对扩展开放,对修改关闭。就是指在尽量不修改代码的情况下进行功能的扩展。

里氏代换原则:所有引用基类的地方必须能够透明的使用子类的对象。

       在一个软件中,将一个基类对象替换成他的子类对象,程序不会产生任何异常,反之则不成立。里氏代换原则是实现开闭原则的重要方式之一,由于在使用基类对象的地方都可以使用子类对象,所以在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定子类类型,用子类对象替换父类对象。

      在运用该原则时,应该尽量将父类设计为抽象类或者接口,让子类集成父类或者实现父接口,并重写父类方法。在运行时,子类对象替换父类对象。可以方便的扩展系统,又较少的改动代码。

工厂模式可以很好地体现出开闭原则和里氏代换原则。

模式结构

    Product(抽象的产品):是所有产品对象的接口。一句话,这个抽象的产品集合了具体产品的共有的方法。

    ConcreteProduct(具体的产品):是做具体的产品的业务处理,他与具体的产品工厂一一对应。所有的产品都需要重写Product的方法。一句话,具体产品是抽象产品的子类或者实现类。

    Factory(抽象的工厂):在这个工厂中声明了工厂方法,该方法返回一个抽象的产品。抽象工厂是工厂方法的核心,所有的具体工厂都要实现该接口。一句话,抽象工厂里面工厂方法作用在于创建产品对象,它的返回值是抽象的产品。

    ConcreteFactory(具体的工厂):它是抽象工厂的子类,重写了在抽象工厂声明的方法,并交由客户端调用,返回一个具体产品的实例。一句话:它是抽象工厂的子类,主要作用就是创建具体的产品对象(即返回值就是具体的产品)。

总结就是:有工厂与产品的一一对应关系,抽象工厂创建抽象产品,具体工厂创建具体产品。

举例说明

   场景:在日志记录中,可能需要进行不同场景的日志记录,比如有时需要文件日志记录,有时需要数据库日志记录。此时为了尽可能的满足开闭原则,则可以使用工厂方法模式。

    创建一个抽象的日志产品:日志不仅仅需要记录,有需要定期清理过期的日志。那么这两个方法可以抽取出来。

package com.gm.factory.method;

/**
 * 日志产品,充当抽象的产品
 */
public interface LoggerProduct {

    /**
     * 记录日志,每个系统都会进行日志记录
     */
    public void writeLog();

    /**
     * 清理日志,部分系统将遗留的日志进行清理
     */
    public void cleanLog();

}

    创建一个文件日志记录器,充当具体的产品。

package com.gm.factory.method;

/**
 * 文件日志记录, 重当具体的产品
 */
public class FileLogger implements LoggerProduct {

    /**
     * 记录日志
     */
    @Override
    public void writeLog() {
        System.out.println("文件日志记录完成");
    }

    /**
     * 清理日志
     */
    @Override
    public void cleanLog() {
        System.out.println("清理过期文件日志完成");
    }
}

创建一个数据库日志记录器,充当具体的产品

package com.gm.factory.method;

public class DBLogger implements LoggerProduct {
    /**
     * 记录日志
     */
    @Override
    public void writeLog() {
        System.out.println("数据库日志记录完成");
    }

    /**
     * 清理日志
     */
    @Override
    public void cleanLog() {
        System.out.println("清理数据库过期日志完成");
    }
}

创建一个抽象的日志记录器工厂,充当抽象的工厂,专门创建文件记录器工厂。

package com.gm.factory.method;

/**
 * 日志工厂,充当抽象的工厂
 */
public interface LoggerFactory {

    /**
     * 创建日志记录器,声明的工厂方法
     * @return
     */
    public LoggerProduct createLogger();
}

创建一个文件日志记录器工厂,专门创建文件记录器对象。

package com.gm.factory.method;

/**
 * 文件记录器工厂,充当具体的工厂
 */
public class FileLggerFactory implements LoggerFactory {
    /**
     * 创建文件记录器, 创建具体的产品对象
     * @return
     */
    @Override
    public LoggerProduct createLogger() {
        return new FileLogger();
    }
}

创建一个数据库日志记录器的工厂,专门创建数据源日志记录器对象。

package com.gm.factory.method;

/**
 * 数据源产品工厂,充当具体的工厂
 */
public class DBLoggerFactory implements LoggerFactory {

    /**
     * 创建数据源日志记录器,创建具体的产品
     * @return
     */
    @Override
    public LoggerProduct createLogger() {
        return new DBLogger();
    }
}

此时,我们有工厂与产品的一一对应关系,抽象日志工厂创建抽象日志产品,文件工厂创建文件产品,数据库工厂创建数据库产品。

客户端调用

package com.gm.factory.method;

public class Client {
    public static void main(String[] args) throws Exception{

        LoggerFactory factory = (LoggerFactory)Class.forName("com.gm.factory.method.FileLggerFactory").newInstance();
        LoggerProduct loggerProduct = factory.createLogger();
        //记录日志
        loggerProduct.writeLog();
        //有的系统需要删除日志
        loggerProduct.cleanLog();
    }
}

输出结果

文件日志记录完成
清理过期文件日志完成

优劣势

    优势

     1.在工厂方法中,工厂方法创建客户端所需用的产品,而且隐藏了产品实例化过程,客户端只需要关心那个工厂,而不用关心创建细节,更无需关系具体产品的类名。

     2.工厂角色和产品角色的多态性设计,能够让工厂自主决定创建那个产品对象,创建产品对象的细节完全在具体工厂内部完成。

     3.在扩展时,无需对工厂方法进行逻辑改动,只需要扩展具体的功能产品及其对应的具体工厂即可。

缺点:

   1.在扩展时,不仅需要提供功能产品对象,还需要提供具体的创建该产品的工厂,增加系统的复杂度。

   2.因为考虑到扩展性,引入了抽象层(抽象工厂角色,抽象产品角色),增加对系统的理解难度。

适用场景

1.客户端不需要知道具体对象的类名,只需要知道创建该对象的工厂即可。这个工厂可以在数据库或者配置文件中配置。

2.在对象创建比工厂方法多时,即可使用。易于扩展。利用多态和里氏代换原则,使得系统更好的扩展。

 

针对上章节中的简单工厂方法中的场景,如果需要增加支付系统,秒杀系统,账户系统等系统,则扩展性不够强,我们可以创建抽象的系统产品,创建对应的抽象的系统工厂,具体的用户系统,用户工厂,支付系统,支付工厂,账户系统,账户工厂等来进行改造,扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值