东莞凤岗网站建设,怎样进入公众号,如何创建自己的网站,六安百姓网设计模式-结构型
结构型设计模式包含#xff1a;代理模式、适配器模式、桥接模式、装饰模式、外观设计模式、享元模式、组合模式
代理模式
核心是在具体的功能类与使用者之间建立一个中介类作为代理#xff0c;使用者通过代理对象对真实的功能类进行访问。 在iOS开发中代理模式、适配器模式、桥接模式、装饰模式、外观设计模式、享元模式、组合模式
代理模式
核心是在具体的功能类与使用者之间建立一个中介类作为代理使用者通过代理对象对真实的功能类进行访问。 在iOS开发中代理设计模式非常有用在UIKit框架中UITableView 和 UITextView 等组件的渲染和交互都采用了代理设计模式。
以病人预约看病的软件设计举例核心功能类只有两个医生类和病人类病人看病前首先预约预约完成后问诊医生陈述病情然后开药。整个系统中有些行为既不属于病人类也不属于医生类如医生的预约和问诊过程的控制等这时就需要一个代理类代理医生处理这些行为。
重构后
class Patient {func describeCondition() - String {let describe 描述病情print(describe)return describe}
}
class Doctor {func writPrescription(condition: String) - String {let prescription 依据病情: \(condition), 开的处方print(prescription)return prescription}
}
class DoctorProxy {var patient: Patientinit(patient: Patient) {self.patient patient}func seeDoctor() {// 预约医生let doctor reservation()// 病人描述病情let condition self.patient.describeCondition()// 医生开处方doctor.writPrescription(condition: condition)}func reservation() - Doctor {let doctor Doctor()print(预约医生)return doctor}
}
let patient Patient()
let doctorProxy DoctorProxy(patient: patient)
doctorProxy.seeDoctor()
其中病人并没有和医生进行直接交互而是通过中间的代理类 DoctorProxy。实际开发中使用代理设计模式可以使具体的功能类的聚合性更强并可以在某些功能的执行前后进行额外的准备工作和善后工作。
适配器模式
适配器模式并不是软件设计中的最佳实践其主要为了解决软件开发过程中新旧模块不兼容的问题。其定义将一个类的接口转换成使用者期望的另外接口使得原本接口不兼容的类可以一起工作。
当数据模型版本升级时可以使用适配器模式兼容旧的数据模型
重构后
class User {var name: Stringvar age: Int
}
class UserV2 {var nickName: Stringvar age: Intvar address: String
}
class UserAdapter {static func toUserV2(user: User) - UserV2 {return UserV2(nickName: user.name, age: user.age, address: )}
}
let user User(name: 学伟, age: 18)
let userV2 UserAdapter.toUserV2(user: user)
print(userV2)
实际开发中由于数据模型升级造成的代码不兼容问题会经常遇到当项目过于庞大时如果贸然修改以往的旧代码会有很大的工作量同时也会伴随很大的风险使用适配器模式就是一种比较适合的折中选择。
桥接模式
桥接模式是合成复用原则的一种应用其核心是将抽象与实现分离用组合来代替继承关系从而给类更多的扩展性降低类之间的耦合度。 实际开发中当某个类具有多维度的属性时在组织类的结构时使用桥接模式十分适合。 例如汽车从功能上分为轿车和卡车颜色上又分为黑色白色。在设计时有两种设计方案一种是创建轿车和卡车的类每个类包含颜色属性
enum Color {case redcase green
}
class Car {var color: Color
}
class Saloon: Car {print(我是轿车)
}
class Truck: Car {print(我是卡车)
}
另外一种设计方案可以根据桥接模式根据实际需要对功能和颜色进行组合。
重构后
enum Color {case redcase green
}
enum CarType {case salooncase truckvar name: String {switch self {case .saloon:return 轿车case .truck:return 卡车}}
}
protocol CarProtocol {var color: Color { get }var carType: CarType { get }func log()
}
extension CarProtocol {func log() {print(我是 carType.name)}
}
class Car: CarProtocol {var color: Colorvar carType: CarTypeinit(color: Color, carType: CarType) {self.color colorself.carType carType}
}
let car Car(color: .red, carType: .saloon)
car.log()
通过组合颜色和类型两个枚举来构建汽车对象避免了因继承带来的耦合问题。
装饰模式
在不改变对象结构的情况下为该对象增加一些功能。 类比现实生活中的手机壳、壁画...
以为墙添加贴纸的逻辑设计为例
重构后
protocol WallProtocol {func printInfo()
}
class Wall: WallProtocol {func printInfo() {print(墙面)}
}
class StickerDecorator: WallProtocol {var wall: Wallinit(wall: Wall) {self.wall wall}func printInfo() {print(贴纸装饰)self.wall.printInfo()}
}
let wall Wall()
let stickerDecorator StickerDecorator(wall: wall)
stickerDecorator.printInfo()
其中 StickerDecorator 即装饰器也需要完整的实现功能类所实现的接口这样才能不会改变被装饰对象的原始行为。 使用装饰模式可以理解成为对象的行为进行扩展只是相比较于继承装饰模式更加灵活、类之间的耦合度也更低。同时装饰模式可能由于过度设计而增加过多装饰器类使系统复杂性变高。
外观设计模式
在软件设计中当一个系统的功能越来越强时子模块会越来越多应用端对系统的访问也会越来越复杂。这时可以通过提供一个外观类来统一处理这些交互降低应用端使用的复杂性。 以客户购买商品流程的设计为例
struct User {var name: String
}
struct Goods {static func choseGoods(user: User) {print(\(user.name)选择商品)}
}
struct Cashier {static func pay(user: User) {print(\(user.name)付款)}
}
struct Package {static func packing(user: User) {print(\(user.name)打包)}
}
let user User(name: 学伟)
Goods.choseGoods(user: user)
Cashier.pay(user: user)
Package.packing(user: user)
User需要完成一个购物流程需要同时与 Goods 、Cashier、Package 三个类进行交互。当每个模块都变得越来越复杂时代码的扩展和维护将变得十分困难。 对于这样的场景可以定义一个外观类来统一处理用户的购物逻辑。
重构后
...
struct Store {static func shop(user: User) {Goods.choseGoods(user: user)Cashier.pay(user: user)Package.packing(user: user)}
}
let user User(name: 学伟)
Store.shop(user: user)
其中Store 起到外观的作用顾客只需要与 Store 一个类进行交互即可
享元模式
运用共享技术实现大量细粒度对象的复用避免大量重复对象造成系统的资源开销。 在享元模式中需要根据共享性将对象中的数据拆分成内部状态和外部状态之后将内部状态封装成享元对象用户共享。享元模式会增加系统的复杂度对于不会产生大量重复对象的系统并不适用。
以黑白棋设计为例
struct Place {var x: Intvar y: Int
}
enum Color {case Whitecase Black
}
class ChessPiece {var place: Placevar color: Colorvar radius: Doubleinit(place: Place, color: Color, radius: Double) {self.place placeself.color colorself.radius radius}
}
一个棋子除了位置不同外颜色和半径对于大部分棋子来说是相同的这种场景下place 就是 外部状态color与radius为内部状态可以使用享元模式重构
重构后
struct Place {var x: Intvar y: Int
}
enum Color {case Whitecase Black
}
class ChessPieceFlyweight {var color: Colorvar radius: Doubleinit(color: Color, radius: Double) {self.color colorself.radius radius}
}
class ChessPieceFlyweightFactory {static let white ChessPieceFlyweight(color: .White, radius: 16.0)static let black ChessPieceFlyweight(color: .Black, radius: 16.0)static func getChessPieceFlyweight(color: Color) - ChessPieceFlyweight {switch color {case .White:return whitecase .Black:return black}}
}
class ChessPiece {var place: Placevar chessPieceFlyweight: ChessPieceFlyweightinit(place: Place, color: Color) {self.place placeself.chessPieceFlyweight ChessPieceFlyweightFactory.getChessPieceFlyweight(color: color)}
}
即便创建若干个棋子真实的 ChessPieceFlyweight 只有两个随着创建的个数越多节省的内存也越多。
组合模式
采用树状层级结构来表示部分与整体的关系使得无论是整体对象还是单个对象对其访问都具有一致性。 在面向对象设计思想中完整的文件系统至少需要两个类来描述文件夹和文件文件系统实际就是树状层级结构可以使用组合模式设计。
重构后
enum NodeType {case Foldercase File
}
protocol FileNode {var type: NodeType { get }var name: String { get }func addNode(node: FileNode)func removeNode(node: FileNode)func getAllNode() - [FileNode]
}
class file: FileNode {var type: NodeTypevar name: Stringvar child [FileNode]()init(type: NodeType, name: String) {self.type typeself.name name}func addNode(node: FileNode) {self.child.append(node)}func removeNode(node: FileNode) {self.child self.child.filter({ n inif node.name n.name node.type n.type {return false}return true})}func getAllNode() - [FileNode] {return self.child}
}
通过定义统一的 FileNode 接口使得使用方无论关心当前操作的节点是文件夹还是文件都有统一的访问方式而且屏蔽了树结构中层级的概念这是组合模式最大的优势。