代理模式入门

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。

代理有多种类型:

  • 远程代理:为位于不同地址空间或网络上的对象提供本地代表
  • 虚拟代理:根据需要创建开销大的对象
  • 保护代理:根据各种访问权限控制对原对象的访问
  • 智能引用代理:通过对真正对象的引用进行计数来管理内存。也用于锁定真正对象,让其他对象不能对其进行修改

UML类图

静态模式

动态代理模式

代码示例

虚拟代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

/*
使用代理模式自定义实现简单带占位的UIImageView功能:
1. 基于UIView
2. 下载图片过程中展示占位文字
3. 下载完成后绘制图片

*/


protocol ImageDisplay {
func imageWithURL(url:URL)
}

class ImageDisplayProxy: UIView,ImageDisplay {

var imageView:ImageDisplayView?

override init(frame: CGRect) {
imageView = ImageDisplayView.init(frame: frame)
super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

//MARK: ImageDisplay
func imageWithURL(url: URL) {
DispatchQueue.global().async {
sleep(5)
let data = try? Data.init(contentsOf: url as URL)
if let validData = data{
let image = UIImage.init(data: validData, scale: UIScreen.main.scale)
DispatchQueue.main.async {
self.imageView?.image = image
self.imageView?.setNeedsDisplay()
}

}
}
}
}


class ImageDisplayView:UIView,ImageDisplay
{
var url:URL?
var image:UIImage?

func imageWithURL(url: URL) {
self.url = url
}


override func draw(_ rect: CGRect) {
if let validImage = image {
validImage.draw(in: rect)
}else{
let placeholder:NSString = "图片加载中"
placeholder.draw(in: rect, withAttributes: [NSAttributedStringKey.foregroundColor : UIColor.gray])
}
}
}

客户端调用:

1
2
3
4
5
let url = URL.init(string: "https://www.baidu.com/img/540-258%20xinshouye_43194396ba179ef805bcb9950706d2ca.png")

let proxy = ImageDisplayProxy.init(frame: CGRect.init(x: 100, y: 100, width: 100, height: 100))
proxy.imageWithURL(url: url!)
self.view.addSubview(proxy.imageView!)

保护代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
在线交友匹配-保护代理
每个人只能给别人打分,不能给自己打分
每个人只能修改自己的信息,不能修改他人信息

*/
class Person:NSObject {
var name:String
var hotOrNotRating:Int = 0
init(name:String) {
self.name = name
}
}


enum PersonProxyType {
case Owner
case Other
}

enum PersonOperationError:Error {
case IllegalOperation
}


class PersonProxy {
var person:Person
var proxyType:PersonProxyType

init(person:Person,proxyType:PersonProxyType) {
self.person = person
self.proxyType = proxyType
}

func updateHotOrRating(rating:Int) throws -> Void {
if proxyType == PersonProxyType.Owner {
throw PersonOperationError.IllegalOperation
}else{
self.person.hotOrNotRating = rating
}
}

func updateName(name:String) throws -> Void {
if proxyType == PersonProxyType.Other {
throw PersonOperationError.IllegalOperation
}else{
self.person.name = name
}
}

}

客户端调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let person = Person.init(name: "苟兰")
let ownerProxy = PersonProxy.init(person: person, proxyType: .Owner)

do {
try ownerProxy.updateHotOrRating(rating: 10)
} catch PersonOperationError.IllegalOperation{
print("不能修改自己的评分")
} catch{
print(error)
}

print("当前评分:\(person.hotOrNotRating)")
let otherProxy = PersonProxy.init(person: person, proxyType: .Other)
do {
try otherProxy.updateHotOrRating(rating: 10)
} catch {
print(error)
}
print("最新评分:\(person.hotOrNotRating)")

输出结果:

1
2
3
不能修改自己的评分
当前评分:0
最新评分:10