类簇可以说是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中关于数据类型的封装类
从这个UML图来看,貌似和简单工厂模式差不多呢,但是细心观察,这里并没有像简单工厂模式一样违背了开放-封闭原则。在工厂类NSPlaceholderNumber中,提供了创建不种类产品的方法。这点和抽象工厂很像。那和抽象工厂不一样的地方呢?
和抽象工厂的对比
仔细地想下,NSNumber的UML架构就仿佛是将抽象工厂模式中以工厂为单位分割出来的小单位。回到小米和苹果的那个例子,就好像其中的一个产品簇,例如只有苹果公司以及它的iphoneX和MacBook Pro。嘿嘿,看到这里,NSNumber的抽象工厂设计的神秘面纱悄悄地揭开了。
为何这么设计?
刚刚提到了,NSNumber目前只是产品簇中的一条产品线。那么如果以后产生了其他类型的产品线,苹果不需要修改之前的代码,只需要添加另外的工厂和另外的产品线,将开放-封闭原则发挥地玲离尽致。