抽象工厂模式:站在上帝的视角看问题

抽象的科学含义是从众多事物中抽取出公共的本质的特征,而舍弃其非本质的特征的过程。从哲学的角度来说就是分析,综合,运用概念在人脑中再现对象本质的方法。似乎一个强调过程,一个强调方法;这些我们都不需要关心,我们的唯一视角就是:透过现象看本质。

今天介绍的抽象工厂模式和工厂方法模式有异曲同工之妙,可以说抽象工厂模式是工厂方法模式的升级版本。

抽象工厂模式的定义

官方定义:为创建一组相关或相互依赖的对象提供接口,而无须指定它们的具体类。
通俗释义:相似的或者相同的对象,应该都实现一个公共的抽象接口,调用方只关心接口,而不需要知道具体实现。
抽象工厂模式通用类图
通过上面的定义和通用类图,我们可以知道,具体的事物或者对象都应该具有其抽象本质,而我们分析,综合提取出公共本质特征的过程就是抽象工厂模式需要做的事儿,也就是站在上帝视角看问题。

抽象工厂模式的通用代码

/**
 * @Description:抽象工厂,指定创建产品簇
 */
public abstract class AbstractFactory {

    //创建产品A
    public abstract AbstractProduct createProductA();
    //创建产品B
    public abstract AbstractProduct createProductB();
}
/**
 * @Description:代理工厂创建产品对象
 */
public class ConcreateFactory extends AbstractFactory{
    @Override
    public AbstractProduct createProductA() {
        return new ConcreateProductA();
    }

    @Override
    public AbstractProduct createProductB() {
        return new ConcreateProductB();
    }
}

/**
 * @Description:定义公共抽象产品
 */
public abstract class AbstractProduct {

    //抽象接口定义
    public abstract void createProduct();
    //通用公共代码
    public void otherMethod(){
        //do something
    }
}

/**
 * @Description:具体产品A类
 */
public class ConcreateProductA extends AbstractProduct {
    @Override
    public void createProduct() {
        //产品A逻辑
    }
}

/**
 * @Description:具体产品B类
 */
public class ConcreateProductB extends AbstractProduct {
    @Override
    public void createProduct() {
        //产品B逻辑
    }
}
/**
 * @Description:上帝视角
 */
public class GodClient {

    public static void main(String[] args) {
        //指定代理工厂
        AbstractFactory factory = new ConcreateFactory();
        //创建产品对象
        AbstractProduct productA = factory.createProductA();
        AbstractProduct productB = factory.createProductB();
        //实现产品逻辑
        productA.createProduct();
        productB.createProduct();
    }
}

以上就是抽象工厂模式的通用代码,可以进行扩展,比如增加一个产品C,则改动点,可想而知。

抽象工厂模式的应用场景

1.由定义可知,抽象工厂模式是为了解决一个产品簇的问题,也就是说,一个对象簇或者一类相互约束的对象,都可以有相同的约束和抽象,就可使用抽象工厂模式进行设计。
2.定义了一组抽象方法类,但是具体的功能还不太明确的情况下,可以使用抽象工厂模式,也就是先将框架抽象出来,再进行具体细节的创造实现。

抽象工厂模式的优缺点

优点
1.封装性。关心接口而非实现。产品由工厂类负责创建,所以产品创建只需要知道哪个工厂类就可以创建产品。
2.内聚性。也就是所有的产品都有自己实现的细节,每个工厂类创建具体的产品。细节上实现内聚,将交互放在抽象层面。
缺点
抽象工厂模式最大的且最致命的确定就是产品族的扩展非常难。比如说要增加一个产品,看看我们的程序改动地方都有哪些,改动是非常大的,这就违反了开闭原则,有些文章中又说是符合开闭原则的,因为针对客户端是是符合开闭原则的,再此不做深究。

抽象工厂模式的经典应用

抽象工厂在Java代码中也比较常见,例如我们熟知的数据库连接对象java.sql.Connection,java.sql.Statement,java.sql.ResultSet;以及xml包下的一些类,比如:javax.xml.parsers.DocumentBuilderFactory,javax.xml.transform.TransformerFactory等,有兴趣可深入研究一波,加深对抽象工厂模式的理解和运用。

工厂模式的比较

在这里有必要对一些概念进行一个澄清,尽管看上去颇为相似,但是每个概念所代表的的含义都不尽相同,通过比较说明这些差异,不会在概念上出现混淆和误解。以下的内容参考:https://refactoringguru.cn/design-patterns/factory-comparison

工厂

工厂是一个含义模糊的术语,在此表示技术意义上的概念, 表示可以创建一些东西的函数、 方法或类。 最常见的情况下, 工厂创建的是对象。 但是它们也可以创建文件和数据库记录等其他东西。

例如, 下面这些东西都可以非正式地被称为 “工厂”:

  • 创建程序 GUI 的函数或方法;
  • 创建用户的类;
  • 以特定方式调用类构造函数的静态方法。
  • 一种创建型设计模式。

当某人说到 “工厂” 这个词时, 其具体含义通常可以根据上下文来确定。 但如果你有疑问, 可以直接提问。 毕竟作者本人有时候也没有搞清楚。

构建方法

构建方法在 《重构与模式》 中被定义为 “创建对象的方法”。 这意味着每个工厂方法模式的结果都是 “构建方法”, 但反过来则并非如此。 这也意味着你可以用 “构建方法” 来替代马丁·福勒在重构中使用的 “工厂方法” 和乔斯华·布洛克在 《Effective Java》 中使用的 “静态工厂方法”。

在实际中, 构建方法只是构造函数调用的封装器。 它可能只是一个能更好地表达意图的名称。 此外, 它可以让你的代码独立于构造函数的改动, 甚至还可以包含一些特殊的逻辑, 返回已有对象以而不是创建新对象。

许多人会仅仅因为这些方法创建了新对象而称之为 “工厂方法”。 其中的逻辑很直接: 所有的工厂都会创建对象, 而该方法会创建对象, 所以显然它是一个工厂方法。 当遇到真正的工厂方法时, 这自然会造成许多混淆。

/**
 * @Description:next构建方法
 */
public class Number {
    private int value;

    public Number(int value) {
        this.value = value;
    }
    
    public Number next(){
        return new Number(value + 1);
    }
}

静态构建方法

静态构建方法是被声明为 static的构建方法。 换句话说, 你无需创建对象就能在某个类上调用该方法。

不要因为某些人将这些方法称为 “静态工厂方法” 而被其迷惑。 这种称呼只是一个坏习惯。 工厂方法是一种依赖于继承的设计模式。 如果将它设置为 static , 你就不能在子类中对其进行扩展, 这就破坏了该模式的目的。
当静态构建方法返回一个新对象时, 它就成为了构造函数的替代品。

在下列情况中, 这可能会非常实用:
你必须针对不同的目的提供多个不同的构造函数, 但是其签名相同时。 例如, 在 Java、 C++、 C# 以及其他许多语言中不可能同时存在 Random­(int max) 和 Random­(int min) 函数。 最常用的变通方式是创建多个调用默认构造函数的静态方法, 并于稍后再设置适当的数值。

你希望复用已有对象而不是初始化新对象时 (参考单例模式)。 绝大多数编程语言的构造函数必须都返回一个新的类实例。 静态构建方法是应对该限制的变通方法。 在静态方法内部, 你的代码会决定是调用构造函数创建一个全新实例, 还是返回一个在缓存中已有的对象。

/**
 * @Author: Max
 * @Date: 2020-09-06 10:34
 * @Description:静态构建方法示例
 */
public class AdminUser extends User{
    private Long id;
    private String name;
    
    public AdminUser(Long id,String name){
        this.id = id;
        this.name = name;
    }
    public static AdminUser load(Long id){
        AdminUser adminUser = queryCacheById(id);
        return adminUser;
    }
}

简单工厂模式

简单工厂模式 描述了一个类,它拥有一个包含大量条件语句的构建方法, 可根据方法的参数来选择对何种产品进行初始化并将其返回。

人们通常会将简单工厂与普通的工厂或其它创建型设计模式混淆。 在绝大多数情况下, 简单工厂是引入工厂方法抽象工厂模式时的一个中间步骤

简单工厂通常没有子类。 但当从一个简单工厂中抽取出子类后, 它看上去就会更像经典的工厂方法模式了。
顺便提一句, 如果你将一个简单工厂声明为 abstract 类型, 它并不会神奇地变成抽象工厂模式。
这里给出一个简单工厂的例子:

public class UserFactory {
    public static User create(int type) throws Exception{
        switch (type){
            case 1:
                return new AdminUser();
            case 2:
                return new CustomerUser();
            case 3:
                return new xiaoerUser();
            default: throw new Exception("用户类型错误");
        }
    }
}

工厂方法模式

工厂方法是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
如果在基类及其扩展的子类中都有一个构建方法的话, 那它可能就是工厂方法。具体参考工厂模式

抽象工厂模式

抽象工厂是一种创建型设计模式, 它能创建一系列相关或相互依赖的对象, 而无需指定其具体类。

什么是 “系列对象”? 例如有这样一组的对象: ​ 运输工具 + 引擎 + 控制器 。 它可能会有几个变体:

  1. 汽车 + 内燃机 + 方向盘
  2. 飞机 + 喷气式发动机 + 操纵杆

如果你的程序中并不涉及产品系列的话, 那就不需要抽象工厂。
再次重申, 许多人分不清抽象工厂模式和声明为 abstract 的简单工厂。 不要犯这个错误!

猜你喜欢

转载自blog.csdn.net/weixin_30484149/article/details/108427447