设计模式 - 工厂方法模式

栏目: 后端 · 发布时间: 6年前

内容简介:工厂方法包含了一下角色还是拿售卖机票举例,我们之前用简单工厂实现了不同供应商的下单逻辑,但是随着业务的不断扩大,我们对接的供应商越来越多,这样就会造成每次对接一个供应商都会在工厂类中添加分支,对工厂类进行修改,这就违反了输出
  • 工厂方法模式是类的创建模式,又叫虚拟构造器(Virtual Constructor)模式,或者多态性工厂模式。
  • 定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

结构

设计模式 - 工厂方法模式

工厂方法包含了一下角色

  • Product:抽象产品
  • ConcreteProduct:具象产品
  • Factory:抽象工厂
  • ConcreteFactory:具象工厂

场景示例

还是拿售卖机票举例,我们之前用简单工厂实现了不同供应商的下单逻辑,但是随着业务的不断扩大,我们对接的供应商越来越多,这样就会造成每次对接一个供应商都会在工厂类中添加分支,对工厂类进行修改,这就违反了 开闭原则 ,所以现在我们用工厂方法来修改一下。 Factory 代码

public interface Factory {

    Product createProduct();
}
public class AFactory implements Factory {

    @Override
    public Product createProduct() {
        return new AProduct();
    }
}
public class BFactory implements Factory {
    @Override
    public Product createProduct() {
        return new BProduct();
    }
}
public class CFactory implements Factory {
    @Override
    public Product createProduct() {
        return new CProdut();
    }
}
... D
... E
复制代码

Product代码

public interface Product {

    void createOrder();
}
public class AProduct implements Product {
    @Override
    public void createOrder() {
        System.out.println("供应商A:下单操作");
    }
}
public class BProduct implements Product {
    @Override
    public void createOrder() {
        System.out.println("供应商B:下单操作");
    }
}
public class CProdut implements Product {
    @Override
    public void createOrder() {
        System.out.println("供应商B:下单操作");
    }
}
... D
... E
复制代码

Client 代码

public class Client {
    public static void main(String[] args) {
        Factory aFactory = new AFactory();
        Product aProduct = aFactory.createProduct();
        aProduct.createOrder();
        Factory bFactory = new BFactory();
        Product bProduct = bFactory.createProduct();
        bProduct.createOrder();
    }
}
复制代码

输出 供应商A:下单操作 供应商B:下单操作 以上就是一个简单的工厂方法的实现。即使在添加新的供应商,我们只要创建新的供应商工厂以及其实现就可以了,这样对我们的整个的工厂和产品体系都没有发生修改,而只是扩展了变化,这就完全符合了 开放-闭合 原则。如果我们的需求发生了变化,要同时支持单程、往返的下单,只要我们在每一个供应商作为一个简单工厂,创建出支持单程、往返的两种具象的产品就可以了。但是我们仔细观察就能发现, 工厂方法模式实现时,客户端需要决定实例化哪一个工厂,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来运行,你想要什么功能,本来是去修改工厂的,但是现在是去修改了客户端!

此例只是针对每个工厂只生成一个具象产品类,至于一个工厂生成多个具象产品类可将每个工厂改造成简单工厂,具体可参考 披萨店 。 消除分支判断可以利用 反射 的方法。(将在抽象工厂章节统一列出)

优点

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

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

  • 遵循 开放-闭合 原则,在系统中新增加一个产品时,不用更改抽象工厂以及抽象产品,也不用对客户端以及具象工厂和产品做修改,而只要添加一个具体工厂和具体产品就可以了。

缺点

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

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

应用场景

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。

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

  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

扩展

  • 使用多个工厂方法,可在抽象工厂中定义多个工厂方法,从而使具体工厂实现不同的工厂方法,哲学工厂方法包含不同的逻辑,创建不同的产品(抽象工厂)
  • 产品对象的重复使用: (1)工厂对象将已经创建过的产品保存到一个集合(如数组、List等)中,然后根据客户对产品的请求,对集合进行查询。如果有满足要求的产品对象,就直接将该产品返回客户端;如果集合中没有这样的产品对象,那么就创建一个新的满足要求的产品对象,然后将这个对象在增加到集合中,再返回给客户端。 (2)Spring单例模式的使用
  • 多态性的丧失和模式的退化:如果工厂仅仅返回一个具体产品对象,便违背了工厂方法的用意,发生退化,此时就不再是工厂方法模式了。一般来说,工厂对象应当有一个抽象的父类型,如果工厂等级结构中只有一个具体工厂类的话,抽象工厂就可以省略,也将发生了退化。当只有一个具体工厂,在具体工厂中可以创建所有的产品对象,并且工厂方法设计为静态方法时,工厂方法模式就退化成简单工厂模式。(本例就可以简化为简单工厂模式)

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Realm of Racket

Realm of Racket

Matthias Felleisen、Conrad Barski M.D.、David Van Horn、Eight Students Northeastern University of / No Starch Press / 2013-6-25 / USD 39.95

Racket is the noble descendant of Lisp, a programming language renowned for its elegance and power. But while Racket retains the functional goodness of Lisp that makes programming purists drool, it wa......一起来看看 《Realm of Racket》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具