GOF设计模式-创建型模式-工厂方法模式

本文介绍Java中的工厂方法模式,指出简单工厂模式违背“开闭原则”、维护测试难的问题。阐述工厂方法模式定义、结构,通过代码示例和实际业务场景说明其应用,还介绍了用配置文件和反射规避违反开闭原则的问题,最后总结其优缺点及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单工厂模式虽然简单,但存在一个很严重的问题。当系统中需要引入新产品时,由于静态 工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违 背“开闭原则”,

而且简单工厂类包含了大量的if—else 代码,导致维护和测试难度增大。如何实现增加新产品而不影响已有代码?工厂方法模式应运而生,本文将介绍 第二种工厂模式——工厂方法模式。

先看一下工厂方法模式的定义:

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个 类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式 (Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式 (Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

多读几遍定义  然后让我们根据定义分析一下工厂方法模式的结构:

 

 

工厂方法模式提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方 法,创建具体的产品对象。

 

 

根据结构我们上代码举个栗子:

 

/**
 * 抽象产品
 */
interface Product    {
    public void writeLog();
}
/**
 *具体产品 具体产品可以有多个
 */
class ConcreteProduct implements Product{
    @Override
 public void writeLog() {
    }
}
/**
 * 抽象工厂
 */
interface Factory    {
    public Product    factoryMethod();
}

/**
 * 具体工厂 具体工厂可以有多个
 */
class ConcreteFactory implements Factory    {
    public Product    factoryMethod()    {
        return new ConcreteProduct();
    }
}


/**
 * 客户端调用:
 */
public static void main(String[] args) {
    Factory factory;
    factory = new ConcreteFactory();
    Product product;
    product = factory.factoryMethod();
}

看到没有  我的工厂是new出来的   我为啥没有把工厂方法写成静态的?为什么?  跟简单工厂方法模式那样对象的创建和使用分离开不好吗?

不能,因为工厂方法实际上是抽象方法,要求由子类来动态地实现,而动态性与static所声明的静态性相冲突

与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是 接口,也可以是抽象类或者具体类

 

最后来个实际业务场景看看:

Sunny软件公司欲开发一个系统运行日志记录器(Logger),该记录器可以通过多种途径保存系 统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志 记录方式。 

工厂方法模式解决UML:

完整代码:

//日志记录器接口:抽象产品 
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 LoggerFactory {
    public Logger createLogger() {
        //连接数据库,代码省略 
 // 创建数据库日志记录器对象 
 Logger logger = new DatabaseLogger();
        //初始化数据库日志记录器,代码省略 
 return logger;
    }
}

//文件日志记录器工厂类:具体工厂 
class FileLoggerFactory implements LoggerFactory {
    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();
    }
}

 

这时候Client这头我要切换日志打印形式怎么办?

把factory = new FileLoggerFactory(); 改成 factory = new DatabaseLoggerFactory ();

是不是违反开闭原则了,我们改代码了!

这种违反开闭原则的问题我们可以通过 配置文件+java反射的方式 规避它  这样 我们业务变动是不会变代码,只需变配置:

配置文件中:

<!— config.xml -->  

<?xml version="1.0"?>  

<config>      

<className>FileLoggerFactory</className>  

</config>

代码中:

//通过类名生成实例对象并将其返回 

 Class c=Class.forName(cName);

 Object obj=c.newInstance();              

 return obj; 

工厂方法模式总结:

 

工厂方法模式的主要优点如下:

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

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

(3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品 提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具 体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

1. 主要缺点

工厂方法模式的主要缺点如下:

(1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统 中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行, 会给系统带来一些额外的开销。

(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义, 增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统 的实现难度。

1. 适用场景 在以下情况下可以考虑使用工厂方法模式:

(1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的 类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类 的类名存储在配置文件或数据库中。

(2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要 提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和 里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值