印象:设计模式

132 阅读3分钟

1, 工厂方法,抽象工厂,简单工厂的区别和联系?

工厂与工厂方法,较简单

工厂方法中,给一些描述信息,返回具体的对象

描述信息,就是传参,说一下啥情况


// 工厂,可以方便的创建对象

public class AnnotationFactory {

  // 工厂方法,返回一个具体的对象
  public func createBusinessMapViewModel(for business: YLPBusiness) -> BusinessMapViewModel? {

    guard let yelpCoordinate = business.location.coordinate else {

      return nil

    }


    let coordinate = CLLocationCoordinate2D(latitude: yelpCoordinate.latitude,

                                            longitude: yelpCoordinate.longitude)

    let name = business.name

    let rating = business.rating

    let image: UIImage

    switch rating {

    case 3.0..<3.5:

      image = UIImage(named: "bad")!

    case 3.5..<4.0:

      image = UIImage(named: "meh")!

    default:

      image = UIImage(named: "bad")!

    }


    return BusinessMapViewModel(coordinate: coordinate,

                                image: image,

                                name: name,

                                rating: rating)

  }

}

抽象工厂,更加灵活,包含一组工厂方法。

一般,我们需要一组关联性强的对象时,使用抽象工厂

例子:

工厂 A 和 B, 遵守抽象工厂协议,

( 也可以继承自抽象工厂类 )

具体类工厂 A ( concrete class),提供安卓平台的按钮和图片,

具体类工厂 B ,提供 iOS 平台的按钮和图片,

protocol Btn{
}



protocol Img{
}

struct AndroidBtn: Btn{}

struct AndroidImg: Img{}

struct IOSBtn: Btn{}

struct IOSImg: Img{}

// 抽象工厂
protocol AbstractFactory{

    func btn() -> Btn

    func img() -> Img

}


// 简单工厂
// single factory
struct AndroidFactory: AbstractFactory{


    // 工厂方法
    func btn() -> Btn {

        return AndroidBtn()
    }

    

    func img() -> Img {

        return AndroidImg()
    }

}


struct IOSFactory: AbstractFactory{

    func btn() -> Btn {

        return IOSBtn()
    }

    

    func img() -> Img {

        return IOSImg()
    }
}

多产品,多平台,

多场景下,

使用抽象工厂,将代码组织得好一些

( 把创建的对象,搭配好,不会混淆 )


2, 策略模式( Strategy Pattern ),最简单的设计模式

策略模式的精华, 是使用组合,不要继承

使用 has a , 解耦 is a

策略模式,让方法独立于使用者( client )

策略模式, 也是代码重用的一种方式

让代码的粒度,更细

例子一,

从这样,



protocol Person{

    func rename()

    func doSth()

    func eatSth()

}


extension Person{

    func rename(){

        // 昵称,变一下

    }

}


// 比较标准的写固定
struct Student: Person{

    func doSth(){

        // 读书

    }

    

    func eatSth(){

        // 甜食

    }

}


struct Workman: Person{

    func doSth(){

        // work

    }

    

    func eatSth(){

        // 吃香的,喝辣的

    }

}



struct Lady: Person{

    func doSth(){

        // work

    }


    func eatSth(){

        // 甜食

    }

}

到这样

protocol Person{

    var doHabit: ToDo{get  set}

    var eatPreference: ToEat{get set}

}



protocol ToDo{

    func doSth()

}



protocol ToEat{

    func eatSth()

}




struct ReadHabit: ToDo{

    func doSth() {

        // read

    }

}


struct WorkHabit: ToDo{

    func doSth() {

        // work

    }

}



struct SugerPreference: ToEat{

    func eatSth() {

        // 甜食

    }

}



struct PepperPreference: ToEat{

    func eatSth() {

        // 吃香的,喝辣的

    }

}



struct Student: Person{

    var doHabit: ToDo = ReadHabit()

    var eatPreference: ToEat = SugerPreference()

}



struct Workman: Person{

    var doHabit: ToDo = WorkHabit()

    var eatPreference: ToEat = PepperPreference()

}


struct Lady: Person{

    var doHabit: ToDo = WorkHabit()

    var eatPreference: ToEat = SugerPreference()

}

如果添加更多的类型,老者 / 歪果仁,

后一种的写法,更清晰

代码的可重用性,更好

例子二, 苹果的 UIViewController 和 UIView

UIViewController has a UIView

苹果建立了控制器 UIViewController,

苹果没有把 UIViewController 作为一种特殊的 UIView.

这也可以说, MVC

例子 3, 苹果的 CALayer 和 UIView

UIView has a CALayer

UIView 没有直接继承 CALayer

3, 装饰者, Decorator Pattern

改变对象的方法,在 runtime, 不是在 compile time,

改变对象的行为,不修改原来的对象,那么使用原对象的封装对象

截屏2022-06-07 下午9.40.12.png

装饰者模式,也使用了 has a ( 组合 )

装饰者继承自原对象的类,装饰者还有一个原对象类的属性

例 1: 标准

protocol A{

    func show()

}


protocol DocorateA: A{

    var a: A{get set}

}


struct AOne: A{

    func show() {}

}


struct ATwo: A{

    func show() {}

}



struct DocorateAOne: DocorateA{

    var a: A

    func show(){}

}


struct DocorateATwo: DocorateA{

    var a: A

    func show(){}

}

let a = AOne()

DocorateATwo(a: a).show()
例 2: 好理解些


protocol Fighter{

    func chargeVal() -> Int
}


protocol WeaponLoaded: Fighter{

    var person: Fighter{get set}
}

struct Bear: Fighter{
    func chargeVal() -> Int{
        return 5
    }
}

struct WithSword: WeaponLoaded{

    var person: Fighter

    func chargeVal() -> Int{

        return person.chargeVal() + 66
    }
}

struct WithArrow: WeaponLoaded{

    var person: Fighter

    func chargeVal() -> Int{
        return person.chargeVal() + 6
    }
}

let wong = Fighter()

// 老王带上大宝剑装饰器,战斗力就起来了

WithArrow(person: WithSword(person: wong)).chargeVal()
例 3, 工作中用到的, 即 SnapKit
     self.view.addSubview(box)
     box.snp.makeConstraints { (make) -> Void in
         make.width.height.equalTo(50)
         make.center.equalTo(self.view)
     }

make.width 返回 ConstraintMakerExtendable,

make.width.height 也返回 ConstraintMakerExtendable,

    public var height: ConstraintMakerExtendable {

        self.description.attributes += .height

        return self

    }

这种链式调用,有借鉴装饰者模式

4,观察者, Observer Pattern

( 接收者 Observers ) 消息是被动过来的,push 过来的,

不是( 接收者)自己去 pull 来的

消息源 ( Observable ),需要给订阅消息的接受者,主动发消息

Observable 发生了变化,Observers 收到消息 ( notified )

观察者模式,one to many 结构,一个消息源,多个订阅者

  • Observable 提供 3 个方法:

// 注册就是持有。Observable 持有一个数组的 Observers
1addObserver(_) // 注册, register

2, removeObserver(_) // 取消注册 , unregister
3, notifyObserver()
  • Observer 的方法
update()
  • Observable push 消息,给 Observer

Observable 的 notifyObserver(),

调用注册的 Observer 的 update()

( Observable 拿持有的 Observers 集合,一一调用其 update 方法 )

例子就是 iOS 的 KVO / RxSwift