装饰/原型/外观设计模式简单理解

本文探讨了装饰模式和外观模式的设计理念及其在Cocoa中的应用。装饰模式通过不改变原有对象的方式为其添加新功能,而外观模式则通过提供简单接口来隐藏复杂子系统的内部细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰模式:

给原有的对象添加新的功能,但不继承原有的类。
Cocoa 中 Category 就属于这种设计模式。
举例:实现一个线程安全的数组

模板/原型模式:

某个对象,它的构成/创建十分复杂,可以考虑这种模式。
Cocoa 中 NSCoping 就属于这种模式。
举例: 假设有一个类 Model,它里面有 100 个属性 property1 ~ property100。有个对象 model1,这些属性都已经复制。现在如果需要一个 model2 和 model3 ,它们都与 model1 只有一个属性的值是不同的,那么有一种做法就是 把生成 model1 的 101 行代码复制粘贴两次再修改一下。 还有一种做法,在 Model 类中加一个方法:- (Model *)clone;,然后实现 clone:

- (Model *)clone {
    Model *model = [[self class] init];
    model.property1 = self.property1;
    ...
    model.property100 = self.property100;
    return model;
}
复制代码

这样我们创建其它 model 的时候就可以这样做:

Model *model2 = [model1 clone];
model2.propertyN = xxx;
复制代码

NSCopying 就是这样的。NSCopying 协议使用的时候要注意以下问题,假设 Person 类是这样的:

copyWithZone:的实现:
这样就会出现一个问题,如下所示:

person 的 sons 和 person2 的 sons 完全是同一个对象,假设 sons 可以修改的话,那么修改 person.sons 和 person2.sons 会相互影响。这完全不是我们想要的结果了。我们可以这样做:

修改之后,看下面这段代码的输出:

person.sons 与 person2.sons 是两个不同的数组了。但是里面的元素却是相同的。这里就牵涉到几个比较绕的概念了:

  • 浅拷贝
  • 单层拷贝/单层深拷贝/深拷贝
  • 完全拷贝(可以用归档来处理

感兴趣的话可以自己搜一下。现在我们这种情况属于第二种。

外观/Facade模式(可以解耦)

先举个例子:假设我们要从西安去北京,可以选择自驾/坐飞机/坐火车等方式,都可以去,可以理解为通过不同的手段达到同一个目的,但是细节不同,但是我们不关心它的细节,只关心它的目的。

外观模式使用场景:
有一个复杂的子系统,它为了得到某种结果,里面有很多复杂的逻辑,客户端只想要这个结果,并不关心里面复杂的逻辑。可以写一个中间类,操作这个子系统,客户端只用从中间类来获取结果即可。

外观模式的好处:
解耦合
简化操作

外观模式与适配器模式的区别:
外观模式 -- 意图提供简单的接口
适配器模式 -- 转换接口

举例:
假设我们有一个 Shape 类,和他的一些子类们:

@interface Shape : NSObject

- (void)draw;

@end
****************************************
@interface Rectangle : Shape

@property (assign, nonatomic) CGFloat width;
@property (assign, nonatomic) CGFloat height;

@end

@implementation Rectangle

- (void)draw
{
    绘制一个矩形;
}

@end
****************************************
@interface Circle : Shape

@property (assign, nonatomic) CGFloat radius;

@end

@implementation Circle

- (void)draw
{
    绘制一个圆形;
}

@end
复制代码

假设我们在 ViewController 中写了如下代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //绘制一个矩形
    Rectangle *tangle = [[Rectangle alloc] init];
    tangle.width = 10;
    tangle.height = 20;
    [tangle draw];
    
    //绘制一个圆形
    Circle *cir = [[Circle alloc] init];
    cir.radius = 5;
    [cir draw];
}
复制代码

如果 Shape 有多个子类,比如平行四边形、梯形、八边形等。那么它会是一个特别复杂的系统,并且我们还需要知道这个系统的细节,把数据具体地传递到每个对象对应的属性上才可以。

但其实上我们并不关心在这个系统中它们是怎么实现的,我们就只想让它画个图形就 OK 了。这是可以这么做,创建一个中间类 ShapeMaker:

@interface ShapeMaker : Shape

- (void)drawRectangleWithParams:(NSDictionary *)dic;
- (void)drawCircleWithParams:(NSDictionary *)dic;
- (void)drawRectangleAndCircleWithParams:(NSDictionary *)dic;
...

@end
复制代码

在 ShapeMaker 中去实现这些复杂的操作,ShapeMaker 提供一些简单的接口供 ViewController 使用,ViewController 只用使用接口,传递数据即可,ViewController 并不关心具体实现,也不知道具体每个数据用在哪个地方,它只是让 ShapeMaker 画个形状就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值