原型模式和单例模式
2021-11-22 本文已影响0人
闹鬼的金矿
原型模式和单例模式相对来说比较容易理解,篇幅不多,所以放到一起说。
原型模式主要是为了简化对象的初始化代码,通过合理的封装,来减少调用方的代码量。通常情况下,Objective-C通过NSCopy协议来实现,类型需要实现一个copy方法,会这样写:
- (Student *)copy
{
//创建对象
Student *s = [[Student alloc] init];
//初始化属性
s.cls = self.cls;
s.grade = self.grade;
return s;
}
// 使用copy方法创建一个对象
Student *s = [[Student alloc] init];
Student *copyS = [s copy];
如果Student仅仅继承与NSObject,感觉问题不大。如果情况再复杂一点,Student继承于People。这个时候就需要考虑基类People的属性如何进行初始化,同样如过Sutdent还有子类,子类copy方法中也需要考虑People属性如何初始化。
简单处理:
- (Student *)copy
{
//创建对象
Sutdent *s = [[Student alloc] init];
//初始化父类的属性
s.name = self.name;
s.age = self.age;
//初始化自己的属性
//......//
return s;
}
这样做是可以完成任务,但是还存在一些问题: 每次实现copy方法都需要初始化父类的属性,也就是需要知道父类和父类的父类有什么属性,要去翻父类的代码才能知道,实现起来就比较麻烦。更好的方式是,每个类只需要负责自己的属性初始化,比如:
//People.m
- (void)setup:(People *)p
{
self.name = p.name;
self.age = p.age;
}
- (void)copy
{
People *p = [[People alloc] init];
[p setup:self];
return p;
}
//Student.m
- (void)setup:(Student *)s
{
[super setup:s];
self.class = s.class;
self.grade = s.grade
}
- (void)copy
{
Student *s = [[Student alloc] init];
[s setup:self];
return s;
}
这种方式就简单得多,子类每次实现copy方法重点在于实现setup方法。在setup方法中,父类的属性初始化通过
调用[super setup]完成,不需要子类了解父类有哪些属性,只需要实现自己的属性初始化即可。其实现在用到了模板方法,在这个例子中就是setup方法。模板方法用的其实挺多的,像经常遇到的ViewController声明周期那几个方法就是,平时开发中应该没少重写这几个方法。
总结一下现在这种设计的结构:
原型模式.png接下来接着说单例模式
单例模式在实际开发中也是经常会遇到:
class Single {
let name: String
let id: Int
static let instance = Single()
private init() {
self.name = "123"
self.id = 123
}
}
swift 好像这就结束了,let 定义的属性就是线程安全的。如果是Objective-C,可以考虑使用dispatch_once处理多线程问题。另外如果想绝对保证单例,需要在alloc中去处理多线程的情况:
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
}
return _instance;
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super init];
[_instance setup];
});
return _instance;
}
Reference: Dive into design patterns