暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

这可能是最易理解的工厂模式讲解了

CoderGeshu 2020-12-18
998

『 人生没有白走的路,每一步都算数 


前言

设计模式,是一套被反复使用、多数人知晓的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。

目的是为了提高代码的可重用性、代码的可读性和代码的可靠性

设计模式按其组织结构可以分为创建型、结构型和行为型,其详细分类如下图所示:

设计模式分类

今天就来主要讲讲其中之一——工厂模式,为了让大家能够对工厂模式尽可能地理解掌握,我们就从最简单的工厂模式讲起,配合一个小小的实例,一步步递进到工厂方法模式进而再到抽象工厂模式。好了,话不多说,开始我们的惊喜探索吧!


正文

工厂模式其实也有简易之分,一般是在不同场景下使用不同的工厂模式,从简单和复杂抽象来划分,工厂模式可有:简单工厂模式、工厂方法模式、抽象工厂模式,它们是层层递进不断抽象的,但它们的主要思想是一致的,那就是方便用户获得相应对象而不必要去了解其细节。


简单工厂模式

简单工厂模式的定义:定义一个工厂类, 它可以根据参数的不同返回不同类的实例, 被创建的实例通常都具有共同的父类或者实现了同一个接口。因为在简单工厂模式中用于创建实例的方法是静态(static)方法, 因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式, 它属于类创建型模式。

简单工厂模式的要点:当你需要什么, 只需要传入一个正确的参数, 就可以获取你所需要的对象, 而无须知道其创建细节。

我们通过一个实例来描述一下简单工厂模式的使用:假如我们现在需要开发一个图形界面工具,然后将这个工具提供给一个客户去使用,系统初期我们只需要画一个圆(Circle)和一个三角形(Triangle)即可。那么我们的工具就按照如下的方式设计。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("画一个圆");
        }else if(type.equals("triangle")) {
            System.out.println("画一个三角形");
        }
    }
}

当客户使用时就可以直接按照如下的方式去使用:

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = new Shape();
        shape.draw("circle");
        shape.draw("triangle");
    }
}

过一段时间之后,我们发现我们的工具中需要增加长方形(Rectangle)、正方形(Square)等很多其他的图形。那么这时我们就需要修改我们的 Shape 类。那么我们的 Shape 类会变成如下的样子。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("画一个圆");
        }else if(type.equals("triangle")) {
            System.out.println("画一个三角形");
        }else if(type.equals("...")){
            // 长方形
        }else if(type.equals("...")){
            // 正方形
        }
    }
}

那么如果按照这样的设计将会造成如下的一些缺陷。

  1. 我们的 Shape 类中的代码会因为图形的不断增多,会出现过多的 if{} else{}
    代码块,整个类的代码会非常的多,非常不容易阅读。

  2. Shape 类的职责过重,它负责初始化所有的图形对象,将所有的图形初始化代码放在一个类中,违反“单一职责(一个类或者一个方法只负责执行或完成一个任务)”原则,非常不利于重构及维护。

  3. 当需要增加新的图形时,需要修改 Shape 的源代码,违背开闭原则(开:开放拓展;闭:不能修改原来的代码);

  4. 客户在使用的时候,需要通过 new 关键字来直接创建 Shape 对象,Shape 与客户端的耦合度非常之高;

面对上面的一些缺陷,我们来一个一个的解决。首先,对于图形的不断增多,会增加 Shape 类的代码量、同时不同的图形,其绘制的方法不一样,即职责不一样;所以我们将不同的图形放在不同的类中去实现。

public class Circle {
    public void draw() {
        System.out.println("绘制圆形");
    }
}
public class Triangle {
    public void draw() {
        System.out.println("绘制三角形");
    }
}

客户端调用时按照如下方式去调用:

public class TestDemo {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();
        Triangle triangle = new Triangle();
        triangle.draw();
    }
}

通过上面的改造我们发现,我们遵循了“单一职责原则”将图形的实现划分到了不同的图形类中,但是这种实现中,客户使用时需要知道所有的图形类,并且需要通过new关键字来实例化具体的图形,我们的工具中的具体实现类与客户程序的耦合度非常的高。接下来我们再做一些改造,让客户的使用与具体的图形实现类解耦。
首先我们声明一个图形(Shape)接口如下:

public interface Shape {
    /**
     * 绘制图形
     */

    void draw();
    /**
     * 擦除图形
     */

    void erase();
}

具体图形类实现该接口,示例如下:

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }

    @Override
    public void erase() {
        System.out.println("擦除圆形");
    }
}

public class Triangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制三角形");
    }

    @Override
    public void erase() {
        System.out.println("擦除三角形");
    }
}

要让客户端与具体的实现类之间解耦,那么我们就需要重新创建一个类,通过这个类来获取具体的图形实例,然后将图形对象提供给客户端使用即可,这个类我们就称之为简单工厂

public class ShapeFactory {
    public static Shape getShape(String type) {
        if(type.equals("triangle")) {
            return new Triangle();
        }else if(type.equals("circle")) {
            return new Circle(10);
        } else {
            System.out.println("不支持的类型");
            return null;
        }
    }
}

上述代码的组织结构图如下:

简单工厂组织结构图

简单工厂模式结构中的角色:

  1. Factory(工厂角色):工厂角色即工厂类(以上示例中的 ShapeFactory), 它是简单工厂模式的核心, 负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用, 创建所需的产品对象;在工厂类中提供了静态的工厂方法 factoryMethod(), 它的返回类型为具体实现类型的公共接口(如上例中的 Shape 接口)或父类。

  2. 具体类型的公共接口(如 Shape)或父类:他是工厂所创建的所有对象的父类,封装了所有被创建对象的公共方法,该角色的引入大大提高了系统的灵活性,使得工厂类中只需要定义一个通用的工厂方法,因为所有创建的具体对象都是该角色的子类对象,为客户端和具体实现类之间的解耦提供了很大的好处。

  3. 具体实现类(如Circle、Triangle ):它是工厂类创建的目标,所有被创建的对象都充当这个角色的某个具体实现类。具体实现类都实现了一个公共的接口或者都继承了一个公共的父类,它们需要实现接口或父类中声明的抽象方法。

客户端在使用我们的工具时,不需要知道具体的图形类实现,只需要知道我们提供的图形工具中有一个工厂类 ShapeFactory,并且通过一些固定的参数能够获取到想要的图形即可。

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = ShapeFactory.getShape("triangle");
        shape.draw();
        shape.erase();
        shape=ShapeFactory.getShape("circle");
        shape.draw();
        shape.erase();
    }
}

这样我们就实现了一个简单工厂,通过简单工厂,我们实现了客户端与具体实现类的解耦,同时具体类的实现也遵循了“单一职责原则”,同时提高了代码的可读性、降低了代码的复杂度。

简单工厂模式小结

简单工厂模式提供了专门的工厂类用于创建对象, 将对象的创建和对象的使用分离开, 它作为一种最简单的工厂模式在软件开发中得到了较为广泛的应用。

优点:

  • 工厂类包含一些逻辑判断,可以决定在什么时候创建哪一个具体类的实例。

  • 由于简单工厂模式实现了对象的创建和使用分离,所以当增加具体类时,只需要在工厂类中增加对应的创建逻辑,不会影响客户端对工具的使用。

  • 客户端无需知道所创建的具体类,只需要知道具体的类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度上减少使用者的记忆量。

缺点:

  • 具体类实例的创建都放在单一的工厂类中,工厂类的职责过重;

  • 当具体类变得越来越多时,工厂类的代码量会越来越庞大,不利于阅读和维护;

  • 当增加新的具体类时,都需要修改工厂类将新的具体类的实例创建方式在工厂类中实现,不符合“开闭原则”;

  • 简单工厂模式由于使用了静态工厂方法, 造成工厂角色无法形成基于继承的等级结构。

适用场景:

  • 工厂类负责创建的对象比较少, 由于创建的对象较少, 不会造成工厂方法中的业务逻辑太过复杂。

  • 客户端只知道传入工厂类的参数, 对于如何创建对象并不关心。


工厂方法模式

上文我们简单介绍了简单工厂模式。简单工厂模式虽然简单,但是它存在一个非常严重的问题,即当系统引入新的具体实现类时,由于静态工厂方法通过所传入参数的不同来创建不同的实例,那么我们就不得不去修改工厂类的源代码,这违背了“开闭原则”,那么如何实现在增加具体类的同时不影响原来的代码呢?工厂方法模式(Factory Method Pattern)应运而生。

简单工厂模式只提供了一个工厂类,该工厂类处于对具体类进行实例化的核心位置,它需要知道所有具体类的实例化细节,并决定何时实例化哪一个具体类。新的具体类的添加,务必需要修改工厂类,增加新的具体类的创建逻辑,违背“开闭原则”;简单工厂模式只有一个工厂类,工厂类的职责过重,同时所有具体类的实例化都在一个工厂类中实现,工厂类与具体类的耦合严重,严重影响了系统的灵活性与拓展性,而工厂方法模式则可以很好的解决这一问题。

在我们详述工厂方法模式的概念之前,我们先对以上的简单工厂模式的例子进行一个改造。

(1)对于具体类及具体类的接口(Shape、Circle、Triangle),我们不做修改,保持原来的代码不动。

(2)增加一个工厂接口 ShapeFactory,接口中声明一个 getShape 的方法:

public interface ShapeFactory {
    Shape getShape();
}

(3)为每个具体的类(Circle、Triangle)创建一个对应的工厂类并实现工厂接口:

// CircleFactory
public class CircleFactory implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new Circle();
    }
}

// TriangleFactory 
public class TriangleFactory implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new Triangle();
    }
}

(4)客户使用时只需要知道工厂接口以及具体类的工厂类即可创建对应的具体实例:

public class TestDemo {
    public static void main(String[] args) {
        ShapeFactory shapeFactory = new CircleFactory();
        Shape circle = shapeFactory.getShape();
        circle.draw();

        shapeFactory = new TriangleFactory();
        Shape triangle = shapeFactory.getShape();
        triangle.draw();
    }
}

(5)当我们需要增加一个新的类型,如 Rectange 时,那么我们只需要增加具体类以及具体类对应的工厂类即可,无需修改原有的其他任何一行代码。

// Rectange 类
public class Rectange implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制长方形");
    }
    @Override
    public void erase() {
        System.out.println("擦除长方形");
    }
}

// RectangleFactory 工厂
public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new Rectange();
    }
}

客户端如果需要使用新的类型时,只需要通过新增的工厂获得对应实例即可。

public class TestDemo {
    public static void main(String[] args) {
        //...
        ShapeFactory shapeFactory = new RectangleFactory();
        Shape shape = shapeFactory.getShape();
        shape.draw();
        //...
    }
}

上述代码通过对简单工厂模式的改造,就变成了一个工厂方法模式的简单实现,我们可以发现在工厂方法模式中,我们不再提供统一的工厂类来创建所有具体类的实例对象,而是针对不同的具体类实现了不同的工厂,系统提供了一个与具体类相同等级的工厂等级结构

现在其组织结构图如下:

工厂方法模式结构类图

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

工厂方法模式结构中的角色:

  1. 具体类型的公共接口(如 Shape)或父类:他是工厂所创建的所有对象的父类,封装了所有被创建对象的公共方法,该角色的引入大大提高了系统的灵活性,使得工厂类中只需要定义一个通用的工厂方法,因为所有创建的具体对象都是该角色的子类对象,为客户端和具体实现类之间的解耦提供了很大的好处。

  2. 具体实现类(如 Circle、Triangle ):它是工厂类创建的目标,所有被创建的对象都充当这个角色的某个具体实现类。具体实现类都实现了一个公共的接口或者都继承了一个公共的父类,它们需要实现接口或父类中声明的抽象方法。

  3. 工厂接口(如 ShapeFactory):在工厂接口中,声明了工厂方法,用于返回一个具体类。工厂接口是工厂方法模式的核心,所有创建对象的工厂都必须实现这个接口。

  4. 具体工厂(如 CircleFactory、RectangleFactory、TriangleFactory):它是工厂接口(ShapeFactory)的具体实现,实现了工厂接口中的工厂方法,并可由客户端调用,返回一个具体实现类的实例。

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

在客户端代码中, 只需关心工厂类即可, 不同的具体工厂可以创建不同的产品。

工厂方法模式小结

工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,弥补了简单工厂模式的缺点。工厂方法模式是使用频率最高的设计模式之一, 是很多开源框架和 API 类库的核心模式。

优点:

  • 在工厂方法模式中,工厂方法用来创建具体类的实例,同时向客户隐藏了具体类实例化的细节,用户只需要关心具体类对应的工厂,无需关心实例创建的细节以及甚至不需要关心具体类的类名,实现具体类与用户之间的解耦;

  • 基于工厂接口和具体类型的公共接口的多态性设计是工厂方法模式的关键。它能够让工厂能够自主确定创建何种具体实现类的对象,但是具体对象的创建细节又封装到了具体工厂的内部。工厂方法模式被称为多态工厂模式,就正是因为所有的具体工厂类都有一个公共的接口或者父类。

  • 使用工厂方法模式的另外一个优点就是在系统中加入新的具体类时,无需修改原有的代码,只需要增加新类的实现以及新类对应的工厂即可,完全符合“开闭原则”;

缺点:

  • 添加新的具体实现类时,需要添加对应的工厂类,系统中的类的个数会成对增加,在一定程度上增加了系统的复杂度;类的增多就有更多的类需要编译,增加系统的开销;

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

适用场景:

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

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


抽象工厂模式

工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题,但由于工厂方法模式中每个工厂只创建一个具体类的对象,这将会导致系统当中的工厂类过多,这势必会增加系统的开销。此时,我们可以考虑将一些相关的具体类组成一个“具体类族”,由同一个工厂来统一生产,这就是我们本文要说的“抽象工厂模式”的基本思想。

接着来看上文工厂方法模式中我们说的例子,我们现在有这么一个场景:用户的需求变多了,除了要求不同的形状之外,我们还要求创建不同颜色的形状,比如圆形,我们要求红色的圆形、赤橙黄绿青蓝紫等各种各样颜色的圆形。按照我们抽象方法模式的设计方案,那么我们就需要实现各种颜色的形状并实现这些颜色的形状对应的工厂类,这样一来我们系统中会增多非常多的工厂类。看起来如下:

// 具体类的抽象接口
public interface Shape {
    // 接口方法
}

// 普通 Circle
public class Circle implements Shape {
    // 接口方法实现
}
// 红色 Circle
public class RedCircle implements Shape {
    // 接口方法实现
}
// 各种颜色的 Circle...

// 普通 Triangle
public class Triangle implements Shape {
    //接口方法实现
}
// 红色 Triangle
public class RedTriangle implements Shape {
    //接口方法实现
}
// 各种颜色的 Triangle...

// 工厂接口
public interface ShapeFactory {
    Shape getShape();
}
// 普通 CircleFactory
public class CircleFactory implements ShapeFactory {
    // 返回实例
}
// RedCircleFactory
public class RedCircleFactory implements ShapeFactory {
    // 返回实例
}
// 各种颜色的 Circle 的工厂...
// 普通 TriangleFactory 
public class TriangleFactory implements ShapeFactory {
    // 返回实例
}
// RedTriangleFactory 
public class RedTriangleFactory implements ShapeFactory {
    // 返回实例
}
// 各种颜色的 Triangle 的工厂...

那么我们有没有办法对当前的设计方案进行优化,减少一些工厂类的产生呢?我们下面对当前的系统做进一步抽象。以形状为类的级别、颜色为族来对当前系统作进一步改善:

产品结构-产品族

首先我们要以形状为等级、颜色为族来对系统进行进一步抽象。

(1)以形状为等级结构抽象

进行等级抽象我们需要将不同的形状声明为抽象类(等级划分)并实现公共的抽象接口(Shape),然后具体的实现类继承自对应的抽象类:

// 形状公共接口
public interface Shape {
    void draw();
}
// 等级抽象划分
// 圆形抽象类 Circle
public abstract class Circle implements Shape {
    public abstract void draw();
}
// 长方形抽象类 Rectange
public abstract class Rectange implements Shape {
    public abstract void draw();
}
// 其他图形抽象类...

具体的实现类继承自对应的抽象类,继承自不同的抽象类就相当于将类划分为不同的等级,如:

// 具体颜色的 Circle 实现
public class BlueCircle extends Circle {
    @Override
    public void draw() {
        System.out.println("绘制蓝色的圆");
    }
}
public class RedCircle extends Circle {
    @Override
    public void draw() {
        System.out.println("绘制红色的圆");
    }
}

// 具体颜色的 Rectange 实现
public class RedRectange extends Rectange{
    @Override
    public void draw() {
        System.out.println("绘制红色长方形");
    }
}
public class BlueRectange extends Rectange {
    @Override
    public void draw() {
        System.out.println("绘制蓝色长方形");
    }
}

(2)以颜色为具体类族抽象

具体类族的划分我们以颜色为基础,不同类族的对象我们通过对应的具体工厂来创建。所以首先我们需要定义一个抽象工厂,具体工厂(族)实现抽象工厂的方法来生成一组具体对象。

// 抽象工厂 ShapeFactory 
public interface ShapeFactory {
    Shape getCircle();
    Shape getRectange();
}

// RedShapeFactory(它所代表的是红色形状这一族)
public class RedShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new RedCircle();
    }

    @Override
    public Shape getRectange() {
        return new RedRectange();
    }
}

// BlueShapeFactory(它所代表的是蓝色形状这一族)
public class BlueShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new BlueCircle();
    }

    @Override
    public Shape getRectange() {
        return new BlueRectange();
    }
}

// 其他族...

等级以及族类划分完成之后,我么的客户端在使用时只需要知道抽象工厂(ShapeFactory )以及具体工厂(如BlueShapeFactory )就可以获得指定族的所有形状。

public class TestDemo {
    public static void main(String[] args) {
        ShapeFactory redShapeFactory = new RedShapeFactory();
        Shape circle = redShapeFactory.getCircle();
        circle.draw();
        Shape rectangle = redShapeFactory.getRectange();
        rectangle.draw();

        ShapeFactory blueShapeFactory = new BlueShapeFactory();
        Shape blueCircle = blueShapeFactory.getCircle();
        blueCircle.draw();
    }
}

从上面的例子我们就可以知道,抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比, 抽象工厂模式中的具体工厂不只是创建一种具体对象, 它负责创建一组(族)具体对象

上述类组织结构图如下:

抽象工厂模式组织结构图

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或者相互依赖对象的接口,而无需知道他们的具体类,抽象工厂模式也称 Kit 模式,它属于类创建型模式。

在抽象工厂模式中,每个具体工厂都提供了多个工厂方法用于创建多种不同类型的具体对象,这些被创建的对象就构成一个族。

抽象工厂模式结构中的角色:

  1. 抽象工厂:声明一组用于创建一族产品的方法,每个方法对应一种对象;在抽象工厂中声明了多个工厂方法, 用于创建不同类型的对象, 抽象工厂可以是接口, 也可以是抽象类或者具体类,具体实现可参考上例中的 ShapeFactory;

  2. 具体工厂:具体工厂实现了抽象工厂,每个工厂方法返回一个具体对象,一个具体工厂所创建的具体对象构成一个族。具体实现可参考上例中的 RedShapeFactory;

  3. 抽象类接口:提供一组所有类都具有的业务方法,如上述 Shape 接口。

  4. 抽象类:用于实现抽象接口所定义的业务方法(如 Circle 抽象类),但是该角色对于抽象接口定义的方法只做抽象实现,即所有实现都被定义为抽象方法,最终的具体实现全部交给具体类实现。引入该角色主要是为了根据声明不同的抽象类,将类区分为不同的等级结构。

  5. 具体类:该角色继承抽象类,主要用于实现抽象类中声明的抽象方法,完成不同等级结构,不同族的业务方法的具体实现,如上述 BlueCircle 等。

根据我们上面对抽象工厂模式的描述,我们大致能够明白,如果我们在上例的基础上想要增加绿色或者其他颜色的图形时,我们只需要增加一个绿色产品工厂(GreenShapeFactory),同时继承不同的图形抽象类实现不同颜色的图形具体类即可,如下:

// GreenRectange 
public class GreenRectange extends Rectange {
    @Override
    public void draw() {
        System.out.println("绘制绿色长方形");
    }
}

// GreenCircle
public class GreenCircle extends Circle{
    @Override
    public void draw() {
        System.out.println("绘制绿色圆");
    }
}

// GreenShapeFactory
public class GreenShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new GreenCircle();
    }

    @Override
    public Shape getRectange() {
        return new GreenRectange();
    }
}

我们增加这些拓展,并不会影响到原来的代码,这看起来是符合“开闭原则”的;但是我们再深入思考一下,如果我们现在想增加一个新的图形,比如说三角形(Triangle)。而对于我们目前所做的设计来讲,我们将三角形(Triangle)放到任何一个等级机构(即继承自任何一个图形抽象类,如 Circle)都显得有些格格不入。但是我们如果在系统之中增加一个三角形(Triangle)的抽象类并实现不同颜色的三角形(Triangle)类之后我们会发现,我们需要修改所有的抽象工厂,这并不符合“开闭原则”。即在抽象工厂模式中,我们只能够对族进行拓展,在对族进行拓展的情况下,是符合“开闭原则”的,如上例中增加不同颜色的指定图形;但是对类的等级结构做拓展,是不符合“开闭原则”的;

因此使用抽象工厂模式要求设计人员在设计之初就能够全面考虑, 不会在设计完成之后向系统中增加新的等级结构, 也不会删除已有的等级结构, 否则将会导致系统出现较大的修改, 为后续维护工作带来诸多麻烦。

抽象工厂模式小结

抽象工厂模式是工厂方法模式的进一步延伸, 由于它提供了功能更为强大的工厂类并且具备较好的可扩展性, 在软件开发中得以广泛应用, 尤其是在一些框架和 API 类库的设计中, 例如在 Java 语言的 AWT( 抽象窗口工具包) 中就使用了抽象工厂模式, 它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。抽象工厂模式也是在软件开发中最常用的设计模式之一。

优点:

  • 抽象工厂模式隔离了具体类的生成, 使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易, 所有的具体工厂都实现了抽象工厂中定义的那些公共接口, 因此只需改变具体工厂的实例, 就可以在某种程度上改变整个软件系统的行为。

  • 当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。

  • 增加新的族很方便, 无须修改已有系统, 符合“开闭原则”。

缺点:

  • 增加新的等级结构麻烦, 需要对原有系统进行较大的修改, 甚至需要修改抽象层代码,这显然会带来较大的不便, 违背了“开闭原则”。

使用场景:

  • 一个系统不应当依赖于具体类实例如何被创建、 组合和表达的细节, 这对于所有类型的工厂模式都是很重要的, 用户无须关心对象的创建过程, 将对象的创建和使用解耦;

  • 系统中有多于一个的族, 而每次只使用其中某一族。可以通过配置文件等方式来使得用户可以动态改变族, 也可以很方便地增加新的族。

  • 属于同一个族的对象将在一起使用, 这一约束必须在系统的设计中体现出来。同一个族中的对象可以是没有任何关系的对象, 但是它们都具有一些共同的约束, 如同一操作系统下的按钮和文本框, 按钮与文本框之间没有直接关系, 但它们都是属于某一操作系统的, 此时具有一个共同的约束条件:操作系统的类型。

  • 等级结构稳定, 设计完成之后, 不会向系统中增加新的等级结构或者删除已有的等级结构。


【最后】
原文来自如下三篇博客,作者:RonTech,本篇内容对其作有调整并作图辅助。
1.https://blog.csdn.net/zyhlwzy/article/details/80645936
2.https://blog.csdn.net/zyhlwzy/article/details/80689425
3.https://blog.csdn.net/zyhlwzy/article/details/80707488



我是 CoderGeshu,我们下期再见。

分享、点赞、在看

文章转载自CoderGeshu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论