使用Swift进行设计模式:立面模式– iOS开发技巧–中

关于图案

外墙图案是结构图案之一。 它的主要目的是隐藏系统,类或逻辑的复杂性,并在简单的界面后面提供所有功能。 通常,以一种类与代表系统逻辑的其他类相关的方式来实现Facade。 请看一下图:

如您所见,有一类名为Facade类将逻辑与LogicALogicBLogicCLogicC 。 因此,我们的客户仅调用Facade类才能执行在其他类中实现的某些方法。

实作

让我们想象一个简单的场景。 您已经创建了一个名为Super-Photo的出色应用。 应用程序的核心功能之一是使用JPEGPNG扩展名保存/转换图像。 为此,您想用两种方式保存UIImage表示形式。 一种是将其保存为PNG类型,第二种是将其保存为JPEG文件类型。

首先,为了处理我们的图像类型和代码中可能的错误-最好有两个枚举来使我们的代码更整洁,更易读。

 enum ImageSaverError: Error { 
case couldNotCreateDestinationPath
case couldNotCreateJPEGDataFromImage
case couldNotCreatePNGDataFromImage
case couldNotSaveImageInDestinationPath
}

enum ImageType {
case png
case jpeg(compressionQuality: CGFloat)
}

在下一步中,您将需要创建一个类,该类将处理为每个照片扩展名提供的数据:

 class ImageDataProvider { 
func data(from image: UIImage, type: ImageType) throws -> Data {
switch type {
case .jpeg(let compressionQuality):
return try jpegData(from: image, compressionQuality: compressionQuality)
case .png:
return try pngData(from: image)
}
}

private func pngData(from image: UIImage) throws -> Data {
guard let imageData = UIImagePNGRepresentation(image) else { throw ImageSaverError.couldNotCreateJPEGDataFromImage }
return imageData
}

private func jpegData(from image: UIImage, compressionQuality: CGFloat) throws -> Data {
guard let imageData = UIImageJPEGRepresentation(image, compressionQuality) else { throw ImageSaverError.couldNotCreatePNGDataFromImage }
return imageData
}
}

您已经注意到,我们的ImageDataProvider接受imagetype参数,并使用适当的扩展名JPEGPNG创建图像数据。

最后一步是创建保存UIImage所需的类。 因此,我们将其命名为PathProvider

 class PathProvider { 
func createDestinationPath(fileName: String) throws -> URL {
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
throw ImageSaverError.couldNotCreateDestinationPath
}
let destinationPath = path.appendingPathComponent("\(fileName)")
return destinationPath
}
}

好的,现在,我们有两个带有某些逻辑的类。 现在是时候为其创建立面了!

创建一个名为ImageSaverFacade的类:

 class ImageSaverFacade { 
private let pathProvider = PathProvider()
private let dataProvider = ImageDataProvider()

func save(image: UIImage, type: ImageType, fileName: String, overwrite: Bool) throws {
let destinationURL = try pathProvider.createDestinationPath(fileName: fileName)
let imageData = try dataProvider.data(from: image, type: type)
let writingOptions: Data.WritingOptions = overwrite ? (.atomic) : (.withoutOverwriting)
try imageData.write(to: destinationURL, options: writingOptions)
}
}

我们的ImageSaverFacade类具有PathProviderImageDataProvider类的两个私有对象。 因为客户端不需要了解内部逻辑,所以ImageSaverFacade公开给公众的唯一一件事是一种方法:

  • func save(image: UIImage, type: ImageType, fileName: String, overwrite: Bool) throws

这种方法是我们客户唯一关心的事情。

现在让我们继续进行外墙使用部分:

 let imageSaver = ImageSaverFacade() 
let image = UIImage(named: "my_image")!
do {
try imageSaver.save(image: image, type: .png, fileName: "my_file_name", overwrite: true)
} catch {
//handle Error
}
// or
do {
try imageSaver.save(image: image, type: .jpeg(compressionQuality: 1.0), fileName: "my_file_name", overwrite: false)
} catch {
//handle Error
}

结论

请注意,我们的外观涵盖了与提供Data并为文件目标创建有效URL Data相关的逻辑。 因此,使用ImageSaverFacadeUIImage保存为PNGJPEG非常容易。 唯一要做的就是将正确的参数传递给Facade方法。

在许多情况下可以使用立面设计模式。 Facade为您创建了通往复杂系统的简单网关。 通过使用它,您一定可以使您的代码更易于理解和阅读。

卡米尔·威索基(Kamil Wysocki)

软件工程师@光明发明

个人博客电子邮件Twitter Github Stackoverflow