原型模式和单例模式

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

上一篇下一篇

猜你喜欢

热点阅读