MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C 中的设计模式应用

2022-01-251.2k 阅读

一、单例模式在Objective-C中的应用

1.1 单例模式的概念

单例模式是一种创建型设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。在Objective-C开发中,单例模式常用于需要全局唯一实例的场景,比如应用的配置管理、数据缓存等。

1.2 传统实现方式

在Objective-C中,实现单例模式的传统方法是使用静态变量。以下是一个简单的示例:

#import <Foundation/Foundation.h>

@interface Singleton : NSObject

+ (Singleton *)sharedInstance;

@end

@implementation Singleton

static Singleton *sharedSingleton = nil;

+ (Singleton *)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedSingleton = [[self alloc] init];
    });
    return sharedSingleton;
}

@end

在上述代码中,sharedInstance 方法通过 dispatch_once 来确保 sharedSingleton 只被初始化一次。dispatch_once 是GCD(Grand Central Dispatch)提供的一个函数,它接受一个 dispatch_once_t 类型的令牌和一个块。块中的代码只会被执行一次,无论有多少线程同时调用 sharedInstance 方法。

1.3 线程安全问题及解决

在多线程环境下,如果不使用 dispatch_once,传统的单例实现可能会出现线程安全问题。例如,多个线程同时检查 sharedSingleton 是否为 nil,如果都为 nil,则可能会创建多个实例。而 dispatch_once 内部使用了OSSpinLock来保证线程安全,确保无论在多线程环境下,sharedSingleton 只会被创建一次。

1.4 使用ARC和非ARC的差异

在ARC(自动引用计数)环境下,单例的实现相对简单,因为ARC会自动管理对象的内存。但在非ARC环境下,需要特别注意单例对象的内存管理。通常,可以在单例类的 dealloc 方法中释放相关资源,同时在 sharedInstance 方法中进行适当的内存处理,确保单例对象在应用生命周期内不会被意外释放。

二、工厂模式在Objective-C中的应用

2.1 工厂模式的概念

工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建和使用分离。在Objective-C中,工厂模式常用于创建对象时需要复杂初始化逻辑或者根据不同条件创建不同类型对象的场景。

2.2 简单工厂模式

简单工厂模式是工厂模式的一种基础形式,它定义了一个工厂类,用于创建产品对象。以下是一个简单工厂模式的示例,假设我们有一个图形基类 Shape,并派生出 CircleRectangle 两个子类,通过一个简单工厂来创建图形对象:

#import <Foundation/Foundation.h>

@interface Shape : NSObject

- (void)draw;

@end

@implementation Shape

- (void)draw {
    NSLog(@"Drawing a shape.");
}

@end

@interface Circle : Shape

- (void)draw {
    NSLog(@"Drawing a circle.");
}

@end

@interface Rectangle : Shape

- (void)draw {
    NSLog(@"Drawing a rectangle.");
}

@end

@interface ShapeFactory : NSObject

+ (Shape *)createShapeWithType:(NSString *)type;

@end

@implementation ShapeFactory

+ (Shape *)createShapeWithType:(NSString *)type {
    if ([type isEqualToString:@"circle"]) {
        return [[Circle alloc] init];
    } else if ([type isEqualToString:@"rectangle"]) {
        return [[Rectangle alloc] init];
    }
    return nil;
}

@end

在上述代码中,ShapeFactory 类的 createShapeWithType: 方法根据传入的类型字符串创建相应的图形对象。客户端代码可以通过以下方式使用:

Shape *circle = [ShapeFactory createShapeWithType:@"circle"];
[circle draw];

Shape *rectangle = [ShapeFactory createShapeWithType:@"rectangle"];
[rectangle draw];

2.3 工厂方法模式

工厂方法模式在简单工厂模式的基础上,将工厂类的创建方法抽象成抽象方法,由具体的子类实现。这样可以在不修改工厂类的情况下,添加新的产品类型。以下是一个工厂方法模式的示例:

#import <Foundation/Foundation.h>

@interface Product : NSObject

- (void)operation;

@end

@implementation Product

- (void)operation {
    NSLog(@"Performing base operation.");
}

@end

@interface ConcreteProductA : Product

- (void)operation {
    NSLog(@"Performing operation for Product A.");
}

@end

@interface ConcreteProductB : Product

- (void)operation {
    NSLog(@"Performing operation for Product B.");
}

@end

@interface Creator : NSObject

- (Product *)factoryMethod;

@end

@implementation Creator

- (Product *)factoryMethod {
    return nil;
}

@end

@interface ConcreteCreatorA : Creator

- (Product *)factoryMethod {
    return [[ConcreteProductA alloc] init];
}

@end

@interface ConcreteCreatorB : Creator

- (Product *)factoryMethod {
    return [[ConcreteProductB alloc] init];
}

@end

客户端代码使用如下:

Creator *creatorA = [[ConcreteCreatorA alloc] init];
Product *productA = [creatorA factoryMethod];
[productA operation];

Creator *creatorB = [[ConcreteCreatorB alloc] init];
Product *productB = [creatorB factoryMethod];
[productB operation];

2.4 抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。在Objective-C中,当需要创建多个相关产品族时,抽象工厂模式非常有用。以下是一个抽象工厂模式的示例,假设我们有两个产品族:ButtonTextBox,分别有 MacStyleWindowsStyle 两种风格:

#import <Foundation/Foundation.h>

// 产品抽象类
@interface Button : NSObject

- (void)render;

@end

@interface TextBox : NSObject

- (void)render;

@end

// 具体产品类 - Mac风格
@interface MacButton : Button

- (void)render {
    NSLog(@"Rendering a Mac style button.");
}

@end

@interface MacTextBox : TextBox

- (void)render {
    NSLog(@"Rendering a Mac style text box.");
}

@end

// 具体产品类 - Windows风格
@interface WindowsButton : Button

- (void)render {
    NSLog(@"Rendering a Windows style button.");
}

@end

@interface WindowsTextBox : TextBox

- (void)render {
    NSLog(@"Rendering a Windows style text box.");
}

@end

// 抽象工厂类
@interface GUIFactory : NSObject

- (Button *)createButton;
- (TextBox *)createTextBox;

@end

// 具体工厂类 - Mac风格
@interface MacGUIFactory : GUIFactory

- (Button *)createButton {
    return [[MacButton alloc] init];
}

- (TextBox *)createTextBox {
    return [[MacTextBox alloc] init];
}

@end

// 具体工厂类 - Windows风格
@interface WindowsGUIFactory : GUIFactory

- (Button *)createButton {
    return [[WindowsButton alloc] init];
}

- (TextBox *)createTextBox {
    return [[WindowsTextBox alloc] init];
}

@end

客户端代码如下:

GUIFactory *macFactory = [[MacGUIFactory alloc] init];
Button *macButton = [macFactory createButton];
TextBox *macTextBox = [macFactory createTextBox];
[macButton render];
[macTextBox render];

GUIFactory *windowsFactory = [[WindowsGUIFactory alloc] init];
Button *windowsButton = [windowsFactory createButton];
TextBox *windowsTextBox = [windowsFactory createTextBox];
[windowsButton render];
[windowsTextBox render];

三、代理模式在Objective-C中的应用

3.1 代理模式的概念

代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。在Objective-C中,代理模式广泛应用于各种框架中,比如UIKit中的视图控制器之间的交互、网络请求的回调等。

3.2 代理模式的实现

在Objective-C中,实现代理模式通常需要定义一个协议(protocol),代理对象遵循该协议并实现相应的方法。以下是一个简单的代理模式示例,假设我们有一个 Car 类,它的行驶操作可以由代理来完成:

#import <Foundation/Foundation.h>

// 定义协议
@protocol CarDelegate <NSObject>

- (void)carShouldDrive;

@end

@interface Car : NSObject

@property (nonatomic, weak) id<CarDelegate> delegate;

- (void)start;

@end

@implementation Car

- (void)start {
    if ([self.delegate respondsToSelector:@selector(carShouldDrive)]) {
        [self.delegate carShouldDrive];
    }
}

@end

@interface Driver : NSObject <CarDelegate>

- (void)carShouldDrive {
    NSLog(@"The driver is driving the car.");
}

@end

客户端代码使用如下:

Car *car = [[Car alloc] init];
Driver *driver = [[Driver alloc] init];
car.delegate = driver;
[car start];

3.3 代理模式的优点和应用场景

代理模式的优点在于它可以在不改变原始对象的情况下,为其添加额外的功能。例如,在网络请求中,代理可以处理请求的缓存、错误处理等。在UI开发中,代理可以实现视图之间的解耦,使得视图控制器之间的交互更加灵活和可维护。

四、观察者模式在Objective-C中的应用

4.1 观察者模式的概念

观察者模式是一种行为型设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并被自动更新。在Objective-C中,观察者模式常用于实现事件驱动的编程。

4.2 使用NSNotification实现观察者模式

在Objective-C中,NSNotificationCenter 是实现观察者模式的常用方式。以下是一个简单的示例,假设我们有一个 Publisher 类发布通知,Subscriber 类接收通知:

#import <Foundation/Foundation.h>

@interface Publisher : NSObject

- (void)publishNotification;

@end

@implementation Publisher

- (void)publishNotification {
    NSNotification *notification = [NSNotification notificationWithName:@"MyNotification" object:self userInfo:nil];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
}

@end

@interface Subscriber : NSObject

- (void)handleNotification:(NSNotification *)notification;

@end

@implementation Subscriber

- (void)handleNotification:(NSNotification *)notification {
    NSLog(@"Received notification: %@", notification.name);
}

@end

客户端代码如下:

Publisher *publisher = [[Publisher alloc] init];
Subscriber *subscriber = [[Subscriber alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:subscriber selector:@selector(handleNotification:) name:@"MyNotification" object:nil];
[publisher publishNotification];
[[NSNotificationCenter defaultCenter] removeObserver:subscriber name:@"MyNotification" object:nil];

4.3 使用KVO(Key - Value Observing)实现观察者模式

KVO是Objective-C中另一种实现观察者模式的机制,它主要用于观察对象属性的变化。以下是一个KVO的示例,假设我们有一个 Person 类,其 age 属性发生变化时,观察者会收到通知:

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, assign) NSInteger age;

@end

@implementation Person

@end

@interface Observer : NSObject

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context;

@end

@implementation Observer

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"age"]) {
        NSLog(@"The person's age has changed. New age: %ld", (long)[change[NSKeyValueChangeNewKey] integerValue]);
    }
}

@end

客户端代码如下:

Person *person = [[Person alloc] init];
Observer *observer = [[Observer alloc] init];
[person addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
person.age = 25;
[person removeObserver:observer forKeyPath:@"age"];

4.4 观察者模式的优缺点

观察者模式的优点在于它实现了对象之间的解耦,使得系统的可维护性和可扩展性增强。当一个对象的状态变化时,所有依赖它的对象都会自动更新,无需手动逐个通知。然而,观察者模式也存在一些缺点,比如当观察者数量过多时,可能会影响性能,而且调试起来相对困难,因为消息的传递链可能比较复杂。

五、装饰器模式在Objective-C中的应用

5.1 装饰器模式的概念

装饰器模式是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。在Objective-C中,装饰器模式常用于在运行时为对象添加功能。

5.2 装饰器模式的实现

以下是一个装饰器模式的示例,假设我们有一个 Component 类,代表一个基础对象,有 ConcreteComponent 是其具体实现,Decorator 是装饰器的抽象类,ConcreteDecorator 是具体的装饰器:

#import <Foundation/Foundation.h>

// 组件抽象类
@interface Component : NSObject

- (void)operation;

@end

@implementation Component

- (void)operation {
    NSLog(@"Performing base operation.");
}

@end

// 具体组件类
@interface ConcreteComponent : Component

@end

@implementation ConcreteComponent

@end

// 装饰器抽象类
@interface Decorator : Component

@property (nonatomic, strong) Component *component;

- (instancetype)initWithComponent:(Component *)component;

@end

@implementation Decorator

- (instancetype)initWithComponent:(Component *)component {
    self = [super init];
    if (self) {
        _component = component;
    }
    return self;
}

- (void)operation {
    [self.component operation];
}

@end

// 具体装饰器类
@interface ConcreteDecorator : Decorator

- (void)operation {
    [super operation];
    NSLog(@"Adding additional functionality.");
}

@end

客户端代码如下:

Component *component = [[ConcreteComponent alloc] init];
[component operation];

Decorator *decorator = [[ConcreteDecorator alloc] initWithComponent:component];
[decorator operation];

5.3 装饰器模式与继承的比较

与继承相比,装饰器模式更加灵活。继承是在编译时确定类的行为,一旦类被定义,其功能就固定了。而装饰器模式可以在运行时动态地为对象添加功能,不需要创建大量的子类。例如,在开发图形绘制应用时,可能需要为图形对象添加不同的效果,如阴影、渐变等,使用装饰器模式可以方便地在运行时为图形对象添加这些效果,而不需要为每个效果创建一个子类。

六、策略模式在Objective-C中的应用

6.1 策略模式的概念

策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。在Objective-C中,策略模式常用于根据不同的条件选择不同的算法或行为。

6.2 策略模式的实现

以下是一个策略模式的示例,假设我们有一个 Context 类,它可以根据不同的策略对象执行不同的计算。首先定义策略的抽象协议:

#import <Foundation/Foundation.h>

@protocol Strategy <NSObject>

- (NSInteger)executeWithA:(NSInteger)a b:(NSInteger)b;

@end

然后定义具体的策略类:

@interface AddStrategy : NSObject <Strategy>

- (NSInteger)executeWithA:(NSInteger)a b:(NSInteger)b {
    return a + b;
}

@end

@interface SubtractStrategy : NSObject <Strategy> {

- (NSInteger)executeWithA:(NSInteger)a b:(NSInteger)b {
    return a - b;
}

@end

最后定义 Context 类:

@interface Context : NSObject

@property (nonatomic, strong) id<Strategy> strategy;

- (instancetype)initWithStrategy:(id<Strategy>)strategy;
- (NSInteger)executeWithA:(NSInteger)a b:(NSInteger)b;

@end

@implementation Context

- (instancetype)initWithStrategy:(id<Strategy>)strategy {
    self = [super init];
    if (self) {
        _strategy = strategy;
    }
    return self;
}

- (NSInteger)executeWithA:(NSInteger)a b:(NSInteger)b {
    return [self.strategy executeWithA:a b:b];
}

@end

客户端代码如下:

Context *addContext = [[Context alloc] initWithStrategy:[[AddStrategy alloc] init]];
NSInteger result1 = [addContext executeWithA:5 b:3];
NSLog(@"Add result: %ld", (long)result1);

Context *subtractContext = [[Context alloc] initWithStrategy:[[SubtractStrategy alloc] init]];
NSInteger result2 = [subtractContext executeWithA:5 b:3];
NSLog(@"Subtract result: %ld", (long)result2);

6.3 策略模式的优点和适用场景

策略模式的优点在于它使得算法可以独立于使用它的客户而变化,提高了代码的可维护性和可扩展性。当需要在不同的情况下使用不同的算法,或者算法可能会经常变化时,策略模式是一个很好的选择。例如,在一个电商应用中,根据不同的促销活动选择不同的折扣计算策略,就可以使用策略模式。

七、适配器模式在Objective-C中的应用

7.1 适配器模式的概念

适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户希望的另一个接口。在Objective-C中,适配器模式常用于解决现有类与新接口不兼容的问题。

7.2 对象适配器模式

对象适配器模式通过组合的方式实现适配器功能。以下是一个对象适配器模式的示例,假设我们有一个旧的 Adaptee 类,其接口与新的 Target 接口不兼容,通过 ObjectAdapter 类进行适配:

#import <Foundation/Foundation.h>

// 目标接口
@protocol Target <NSObject>

- (void)request;

@end

// 适配者类
@interface Adaptee : NSObject

- (void)specificRequest;

@end

@implementation Adaptee

- (void)specificRequest {
    NSLog(@"Performing specific request.");
}

@end

// 对象适配器类
@interface ObjectAdapter : NSObject <Target>

@property (nonatomic, strong) Adaptee *adaptee;

- (instancetype)initWithAdaptee:(Adaptee *)adaptee;
- (void)request;

@end

@implementation ObjectAdapter

- (instancetype)initWithAdaptee:(Adaptee *)adaptee {
    self = [super init];
    if (self) {
        _adaptee = adaptee;
    }
    return self;
}

- (void)request {
    [self.adaptee specificRequest];
}

@end

客户端代码如下:

Adaptee *adaptee = [[Adaptee alloc] init];
ObjectAdapter *adapter = [[ObjectAdapter alloc] initWithAdaptee:adaptee];
[adapter request];

7.3 类适配器模式

在Objective-C中,由于不支持多重继承,类适配器模式的实现相对复杂。通常可以通过继承和协议来模拟类适配器的功能。以下是一个简化的类适配器模式示例:

#import <Foundation/Foundation.h>

// 目标接口
@protocol Target <NSObject>

- (void)request;

@end

// 适配者类
@interface Adaptee : NSObject

- (void)specificRequest;

@end

@implementation Adaptee

- (void)specificRequest {
    NSLog(@"Performing specific request.");
}

@end

// 类适配器类
@interface ClassAdapter : Adaptee <Target>

- (void)request {
    [self specificRequest];
}

@end

客户端代码如下:

ClassAdapter *adapter = [[ClassAdapter alloc] init];
[adapter request];

7.4 适配器模式的应用场景

适配器模式在Objective-C开发中常用于集成第三方库时,当第三方库的接口与现有系统的接口不兼容时,可以使用适配器模式进行适配。例如,在开发一个社交分享功能时,不同的社交平台提供的分享接口可能不同,通过适配器模式可以将这些不同的接口适配成统一的接口,方便在应用中调用。

八、桥接模式在Objective-C中的应用

8.1 桥接模式的概念

桥接模式是一种结构型设计模式,它将抽象部分与它的实现部分分离,使它们都可以独立地变化。在Objective-C中,桥接模式常用于处理多层继承结构以及抽象和实现之间的耦合问题。

8.2 桥接模式的实现

以下是一个桥接模式的示例,假设我们有一个图形抽象类 Shape,它有不同的颜色实现。Shape 类通过桥接模式与 Color 类解耦:

#import <Foundation/Foundation.h>

// 颜色抽象类
@interface Color : NSObject

- (void)paint;

@end

@interface RedColor : Color

- (void)paint {
    NSLog(@"Painting with red color.");
}

@end

@interface BlueColor : Color

- (void)paint {
    NSLog(@"Painting with blue color.");
}

@end

// 图形抽象类
@interface Shape : NSObject

@property (nonatomic, strong) Color *color;

- (instancetype)initWithColor:(Color *)color;
- (void)draw;

@end

@interface Circle : Shape

- (void)draw {
    NSLog(@"Drawing a circle.");
    [self.color paint];
}

@end

@interface Rectangle : Shape

- (void)draw {
    NSLog(@"Drawing a rectangle.");
    [self.color paint];
}

@end

客户端代码如下:

Color *redColor = [[RedColor alloc] init];
Shape *redCircle = [[Circle alloc] initWithColor:redColor];
[redCircle draw];

Color *blueColor = [[BlueColor alloc] init];
Shape *blueRectangle = [[Rectangle alloc] initWithColor:blueColor];
[blueRectangle draw];

8.3 桥接模式的优点

桥接模式的优点在于它分离了抽象和实现,使得它们可以独立地扩展。在上述示例中,我们可以独立地添加新的图形类型或者新的颜色类型,而不需要修改现有代码。这提高了代码的可维护性和可扩展性,尤其适用于系统中存在多个维度变化的情况。

九、组合模式在Objective-C中的应用

9.1 组合模式的概念

组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示“部分 - 整体”的层次结构。在Objective-C中,组合模式常用于处理具有层次结构的对象,使得用户对单个对象和组合对象的使用具有一致性。

9.2 组合模式的实现

以下是一个组合模式的示例,假设我们有一个文件系统的模型,File 是叶子节点,Directory 是组合节点:

#import <Foundation/Foundation.h>

@interface FileSystemComponent : NSObject

@property (nonatomic, copy) NSString *name;

- (instancetype)initWithName:(NSString *)name;
- (void)display;

@end

@implementation FileSystemComponent

- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

- (void)display {
    NSLog(@"%@", self.name);
}

@end

@interface File : FileSystemComponent

@end

@implementation File

@end

@interface Directory : FileSystemComponent

@property (nonatomic, strong) NSMutableArray<FileSystemComponent *> *components;

- (void)addComponent:(FileSystemComponent *)component;
- (void)removeComponent:(FileSystemComponent *)component;
- (void)display {
    NSLog(@"Directory: %@", self.name);
    for (FileSystemComponent *component in self.components) {
        [component display];
    }
}

@end

@implementation Directory

- (instancetype)initWithName:(NSString *)name {
    self = [super initWithName:name];
    if (self) {
        _components = [NSMutableArray array];
    }
    return self;
}

- (void)addComponent:(FileSystemComponent *)component {
    [self.components addObject:component];
}

- (void)removeComponent:(FileSystemComponent *)component {
    [self.components removeObject:component];
}

@end

客户端代码如下:

Directory *root = [[Directory alloc] initWithName:@"Root"];

File *file1 = [[File alloc] initWithName:@"File1.txt"];
[root addComponent:file1];

Directory *subDir = [[Directory alloc] initWithName:@"SubDirectory"];
File *file2 = [[File alloc] initWithName:@"File2.txt"];
[subDir addComponent:file2];
[root addComponent:subDir];

[root display];

9.3 组合模式的适用场景

组合模式适用于需要处理具有层次结构的对象的场景,如文件系统管理、组织结构管理等。它使得客户端可以统一地处理单个对象和组合对象,简化了客户端代码,同时提高了系统的可维护性和可扩展性。例如,在一个项目管理系统中,可以使用组合模式来管理项目、子项目和任务之间的层次关系。

十、外观模式在Objective-C中的应用

10.1 外观模式的概念

外观模式是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。在Objective-C中,外观模式常用于简化复杂系统的接口,提高系统的易用性。

10.2 外观模式的实现

以下是一个外观模式的示例,假设我们有一个复杂的多媒体播放系统,包含音频播放器、视频播放器和字幕解析器,通过一个外观类 MediaFacade 来简化使用:

#import <Foundation/Foundation.h>

// 音频播放器类
@interface AudioPlayer : NSObject

- (void)playAudio:(NSString *)audioFile;

@end

@implementation AudioPlayer

- (void)playAudio:(NSString *)audioFile {
    NSLog(@"Playing audio: %@", audioFile);
}

@end

// 视频播放器类
@interface VideoPlayer : NSObject

- (void)playVideo:(NSString *)videoFile;

@end

@implementation VideoPlayer

- (void)playVideo:(NSString *)videoFile {
    NSLog(@"Playing video: %@", videoFile);
}

@end

// 字幕解析器类
@interface SubtitleParser : NSObject

- (void)parseSubtitle:(NSString *)subtitleFile;

@end

@implementation SubtitleParser

- (void)parseSubtitle:(NSString *)subtitleFile {
    NSLog(@"Parsing subtitle: %@", subtitleFile);
}

@end

// 外观类
@interface MediaFacade : NSObject

- (void)playMedia:(NSString *)mediaFile withSubtitle:(NSString *)subtitleFile;

@end

@implementation MediaFacade

- (void)playMedia:(NSString *)mediaFile withSubtitle:(NSString *)subtitleFile {
    AudioPlayer *audioPlayer = [[AudioPlayer alloc] init];
    VideoPlayer *videoPlayer = [[VideoPlayer alloc] init];
    SubtitleParser *subtitleParser = [[SubtitleParser alloc] init];

    [audioPlayer playAudio:mediaFile];
    [videoPlayer playVideo:mediaFile];
    [subtitleParser parseSubtitle:subtitleFile];
}

@end

客户端代码如下:

MediaFacade *facade = [[MediaFacade alloc] init];
[facade playMedia:@"movie.mp4" withSubtitle:@"subtitle.srt"];

10.3 外观模式的优点

外观模式的优点在于它降低了客户端与子系统之间的耦合度,使得客户端只需要与外观类交互,而不需要了解子系统的内部细节。这提高了系统的可维护性和可扩展性,同时也使得系统更加易于使用和理解。例如,在一个大型游戏开发项目中,不同的模块如图形渲染、音频处理、输入管理等可以通过外观模式提供一个统一的简单接口给游戏开发者使用。