类簇

1,147 阅读5分钟

类簇可以说是Objective-C语言中比较重要的设计,Apple在官方文档中用一篇文章来介绍这个概念,尽管文章点到为止,并没有深入到内部机制,但是也用了详细的例子来说明类簇的设计是多么优秀。Apple在文档中称类簇是基于抽象工厂模式来设计的,如果你对抽象工厂的定义不清晰,可能会问,抽象工厂是什么?如果你对抽象工厂的定义清晰,有可能会问,类簇的设计真的是基于抽象工厂模式吗?本文站在设计模式的源头,对类簇进行挖掘解读。

工厂模式

工厂模式一共有三种,简单工厂模式,工厂方法模式,抽象工厂模式。接下来我们依次通过图文并茂的描述进行理解

简单工厂模式

先来看看简单工厂的UML图

我们将简单工厂模式分为几个部分来解读:

产品:

定义了一个抽象的产品类

有两个具体产品类继承了该抽象类

工厂:

creatProduct(String):Product方法:参数为String类型,返回值为Product类型

伪代码实现: if(type == "A") { return new ProductA(); } else { return new ProductB(); }

使用:

伪代码示例:

Product product = factory.creatProduct("A"); product.operation();

可以发现,主要的逻辑代码写在了工厂的方法中,那么如果产品种类增多,我们就需要去修改工厂的方法。回忆一下设计模式六大原则之一的开放-封闭原则,开放指的是面向扩展开放,封闭指的是面向修改封闭。再回到简单工厂模式来看,是不是违背了原则呢。所以在实际应用中,正如它的名字,它仅仅在一些简单场景使用。

工厂方法模式

同样地,我们先来看看工厂方法模式的UML图

同样地,将其分为几个部分来解读:

产品:

定义了一个抽象的产品类 有两个具体产品类继承了该抽象类

工厂:

定义了一个抽象的工厂类 有两个具体工厂类继承了该抽象类

FactoryA类中的+ creatProduct():Product方法伪代码:

return new ProductA();

FactoryB类中的creatProduct():Product方法伪代码:

return new ProductB();

使用:

伪代码演示: // 创建产品A Factory factoryA = new FactoryA(); Product productA = factoryA.creatProduct(); // 创建产品B Factory factoryB = new FactoryB(); Product productB = factoryB.creatProduct();

看完了简单工厂模式和工厂方法模式,通过对比可以发现,工厂方法模式在简单工厂模式的基础之上,践行了开放-封闭原则,创建产品不再通过传入参数判断应该生成哪个具体产品,而是将工厂创建产品的任务放在了子类去做。当增加了新的产品时,我们只需要创建新的子类,实现方法,不需要对抽象类进行修改。

抽象工厂模式

老样子,来看看抽象工厂的UML图

分成三部分来解读抽象工厂模式:

产品:

有两个抽象的产品类

有两个具体产品类分别继承了各自的抽象类

工厂:

定义了一个抽象的工厂类

有两个具体工厂类继承了该抽象类

创建产品的方法,以Factory1类示例:

creatProductA():ProductA方法的伪代码:

return new ProductA1();

creatProductB():ProductB方法的伪代码:

return new ProductB1();

使用:

伪代码演示:

// 型号为1的产品 Factory factory1 = new Factory1();

ProductA productA1 = factory1.creatProductA();

ProductB productB1 = factory1.creatProductB();

// 型号为2的产品

Factory factory2 = new Factory2();

ProductA productA2 = factory2.creatProductA();

ProductB productB2 = factory2.creatProductB();

可以发现,抽象工厂模式其实就是在工厂方法模式的基础上增加了产品的种类,产品的抽象类从一个变成了多个,那么这样一来,产品就构成了一个体系。这个体系有两个关键词,产品簇和产品等级结构,为了理解这两个关键字,我们先来看个实际的例子

产品等级结构: 等级结构就是继承结构,如上图中手机和电脑,有一个抽象类,然后具体的产品继承这个抽象类

产品簇: 上图中iphoneX和MacBook Pro都是产于同一个公司,苹果公司。而小米MIX和小米笔记本Pro也是产于同一家公司。即产品簇的概念是,产于同一家工厂,位于不同产品等级结构中的一组产品。

有了以上的准备知识之后,我们来看看Objective-C中的类簇设计

类簇

在官方文档中,苹果仅仅告诉我们类簇是基于抽象工厂模式来设计的

来看下NSNumber,它是Objective-C中关于数据类型的封装类

对于这个层级的使用者,仅仅能看到一个共有类,那就是NSNumber,所以要分配内存创建合适的子类对象,又怎么可能呢?答案就是这个抽象父类对如何分配进行了处理。抽象父类务必需要定义创建私有子类的方法,这是抽象父类的职责。抽象父类需要基于大家调用的创建方法去分配内存到合适的子类,同时使用者不需要也不能选择对象的类型,统一使用NSNumber来管理。

是简单工厂吗?

从这个UML图来看,貌似和简单工厂模式差不多呢,但是细心观察,这里并没有像简单工厂模式一样违背了开放-封闭原则。在工厂类NSPlaceholderNumber中,提供了创建不种类产品的方法。这点和抽象工厂很像。那和抽象工厂不一样的地方呢?

和抽象工厂的对比

仔细地想下,NSNumber的UML架构就仿佛是将抽象工厂模式中以工厂为单位分割出来的小单位。回到小米和苹果的那个例子,就好像其中的一个产品簇,例如只有苹果公司以及它的iphoneX和MacBook Pro。嘿嘿,看到这里,NSNumber的抽象工厂设计的神秘面纱悄悄地揭开了。

为何这么设计?

刚刚提到了,NSNumber目前只是产品簇中的一条产品线。那么如果以后产生了其他类型的产品线,苹果不需要修改之前的代码,只需要添加另外的工厂和另外的产品线,将开放-封闭原则发挥地玲离尽致。