使用Swift进行设计模式:立面模式– iOS开发技巧–中
关于图案
外墙图案是结构图案之一。 它的主要目的是隐藏系统,类或逻辑的复杂性,并在简单的界面后面提供所有功能。 通常,以一种类与代表系统逻辑的其他类相关的方式来实现Facade。 请看一下图:
如您所见,有一类名为Facade
类将逻辑与LogicA
, LogicB
, LogicC
类LogicC
。 因此,我们的客户仅调用Facade
类才能执行在其他类中实现的某些方法。
实作
让我们想象一个简单的场景。 您已经创建了一个名为Super-Photo
的出色应用。 应用程序的核心功能之一是使用JPEG
或PNG
扩展名保存/转换图像。 为此,您想用两种方式保存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
接受image
和type
参数,并使用适当的扩展名JPEG
或PNG
创建图像数据。
最后一步是创建保存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
类具有PathProvider
和ImageDataProvider
类的两个私有对象。 因为客户端不需要了解内部逻辑,所以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
相关的逻辑。 因此,使用ImageSaverFacade
将UIImage
保存为PNG
或JPEG
非常容易。 唯一要做的就是将正确的参数传递给Facade方法。
在许多情况下可以使用立面设计模式。 Facade为您创建了通往复杂系统的简单网关。 通过使用它,您一定可以使您的代码更易于理解和阅读。
卡米尔·威索基(Kamil Wysocki)
软件工程师@光明发明
个人博客电子邮件Twitter Github Stackoverflow