美文网首页
iOS设计(三)1 设计模式之设计原则

iOS设计(三)1 设计模式之设计原则

作者: shuaikun | 来源:发表于2020-12-03 10:08 被阅读0次
image.png

一、单一职责原则

定义:不同的类具备不同的职责,各司其职。

1、一个类只承担一个职责,如果一个类做了多个职责,有必要的话进行分开。
2、举例说明:

(1)设计目标:设计待支付、待收货、已收货订单列表
(2)设计方案如下:
  方案一:归于一个类里使用if直接进行判断,比较省事
  方案二:各自分职,分成三个类
(3)问题点:方案一中如果每个功能添加新的特殊功能则就会比较麻烦,通过方案二会更好的实现各自的逻辑,更利于后期功能的更迭。

3、代码展示:
import Foundation

class OrderList: NSObject {//订单列表
    var waitPayList: WaitPayList?//待支付
    var waitGoodsList: WaitGoodsList?//待收货
    var receivedGoodsList: ReceivedGoodsList?//已收货
}

class WaitPayList: NSObject {}
class WaitGoodsList: NSObject {}
class ReceivedGoodsList: NSObject {}

二、开闭原则

定义:软件中的对象(类、模块、函数)应该对于扩展是开放的,但是对于修改是封闭的,这意味着一个实体尽量用继承或组合的方式来扩展类的功能,在不改变它的源代码的前提下变更它的行为(如果能保证对整个架构不会产生任何影响,那就没必要搞的那么复杂)。

1、对软件实体的改动,最好用扩展而非修改的方式。
2、举例说明:

(1)设计目标:实现不同支付方式,同时易于扩展
(2)设计方案:
  方案一:根据不同的支付进行判断,然后进行不同的操作
  方案二:设计扩展支付方式来实现不同的支付
(3)问题点:当我们进行删除或添加一个支付方法的时候,方案一每次都要改动pay方法,可以做到,但是方案二只需要增加扩展继承PayProcessor就行了,不需要更改pay方法,更为合理一些

3、代码示例:

(1)修改之前代码

import Foundation

class PayHelper {
    func pay(send: PaySendModel) -> Void {
        if send.type == 0 {
            //支付宝支付
        } else if send.type == 1 {
            //微信支付
        }
    }
}

class PaySendModel {
    var type: Int = 0
    var info: [String: AnyHashable]?
}

(2)代码修改之后

import Foundation

class PayHelper {
    var processors: [Int: PayProcessor]?
    
    func pay(send: PaySendModel) -> Void {
        guard let processors = processors else {return}
        guard let payProcessor: PayProcessor = processors[send.type] else {return}
        payProcessor.handle(send: send)//支付
    }
}

class PaySendModel {
    var type: Int = 0
    var info: [String: AnyHashable]?
}

protocol PayProcessor {
    func handle(send: PaySendModel)
}

class AliPayProcessor: PayProcessor {
    func handle(send: PaySendModel) {
        
    }
}

class WeChatPayProcessor: PayProcessor {
    func handle(send: PaySendModel) {
        
    }
}

代码修改之后,扩展起来是不是很方便,增加支付方式只需要继承PayProcessor,不需要更改pay方法。

三、里氏替换原则

定义:一个对象在其出现的任何地方,都可以用子类实例做替换,并且不会导致程序的错误。

1、子类可以扩展父类的方法,但不应该复写父类的方法。
2、举例说明:

(1)设计目标:设计一个汽车基类,基类里有行驶方法,现有一辆新车继承基类,添加一个获取行驶速度的方法。
(2)设计方案:
(3)问题点:

3、代码展示

(1)代码修改之前

import Foundation

class BaseCar {
    func run() {
        print("汽车跑起来了")
    }
}

class BaoMaCar: BaseCar {
    override func run() {
        super.run()
        print("当前行驶速度是80Km/h")
    }
}

以上方法重写run方法,并且在run方法里增加汽车行驶速度的逻辑,这样是不满足的里氏替换原则的。因为所有基类Car替换成子类BaoMaCar,run方法的行为跟以前不是一模一样了。

(2)代码修改之后

import Foundation

class Car {
    func run() {
        print("汽车跑起来了")
    }
}

class BaoMaCar: Car {
    func showSpeed() {
        print("当前行驶速度是80Km/h")
    }
}

四、接口隔离原则

定义:一个类实现的接口中,包含了它不需要的方法。将接口拆分成更小和更具体的接口,有助于解耦,从而更容易重构、更改。

1、对象不应被强迫依赖它不使用的方法。
2、举例说明:

(1)设计目标:我们定义一个汽车接口,要求实现run等方法。
(2)设计方案:
  方案一:创建车辆基类包含车辆所有功能方法
  方案二:创建车辆类根据不同的车型包含不同的功能方法
(3)问题点:方案一设计比较粗暴且不易区分,因为不同的车型有着不同的功能,如果都用一个协议包含所有方法,代码会变得非常臃肿,且不易维护

3、代码示例:

(1)代码修改之前

import Foundation

protocol ICar {
    func run()
    func showSpeed()
    func playMusic()
}

class Car: ICar {
    func run() {
        print("汽车跑起来了")
    }
    
    func showSpeed() {
        print("当前行驶速度是80Km/h")
    }
    
    func playMusic() {
        print("播放音乐")
    }
}

以上代码定义Car实现了ICar的接口,但是并不是每个车都有播放音乐的功能的,这样对于一般的低端车没有这个功能,对于他们来说,这个接口的设计就是冗余的。
(2)代码修改之后

import Foundation

protocol IProfessionalCar {//具备一般功能的车
    func run()
    func showSpeed()
}

protocol IEntertainingCar {//具备娱乐功能的车
    func run()
    func showSpeed()
    func playMusic()
}

class SangTaNaCar: IProfessionalCar {//桑塔纳轿车
    func run() {
        print("汽车跑起来了")
    }
    
    func showSpeed() {
        print("当前行驶速度是80Km/h")
    }
}

class BaoMaCar: IEntertainingCar {//宝马轿车
    func run() {
        print("汽车跑起来了")
    }
    
    func showSpeed() {
        print("当前行驶速度是80Km/h")
    }
    
    func playMusic() {
        print("播放音乐")
    }
}

接口隔离原则的要求我们,建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。这通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

五、依赖倒置原则

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

1、面向接口编程,提取出事务的本质和共性。
2、举例说明:

(1)设计目标:我们给汽车加油,实现能够加90号的汽油,如果没有,就加93号的汽油
(2)设计方案:
  方案一:创建基类,基类依赖两个底层模块实现目标
  方案二:创建基类,同时创建底层模块和抽象类实现目标
(3)问题点:

3、代码示例:

(1)代码修改之前

import Foundation

class Car {
    func refuel(_ gaso: Gasoline90) {
        print("加90号汽油")
    }
    
    func refuel(_ gaso: Gasoline93) {
        print("加93号汽油")
    }
}

class Gasoline90 {
    
}

class Gasoline93 {
    
}

上面这段代码有什么问题,可以看到Car高层模块依赖了底层模块Gasoline90和Gasoline93,这样写是不符合依赖倒置原则的。

(2)代码修改之后

import Foundation

class Car {
    func refuel(_ gaso: IGasoline) {
        print("加\(gaso.name)汽油")
    }
}

protocol IGasoline {
    var name: String { get }
}

class Gasoline90: IGasoline {
    var name: String = "90号"
}

class Gasoline93: IGasoline {
    var name: String = "93号"
}

修改之后我们高层模块Car依赖了抽象IGasoline,底层模块Gasoline90和Gasoline93也依赖了抽象IGasoline,这种设计是符合依赖倒置原则的。

六、迪米特法则

定义:一个对象对另一个对象了解得越多,那么,它们之间的耦合性也就越强,当修改其中一个对象时,对另一个对象造成的影响也就越大。

1、一个对象应该对其他对象保持最少的了解,实现低耦合、高内聚。
2、举例说明:

(1)设计目标:实现一个给汽车加油的设计,使的我们可以随时保证加油的质量过关
(2)设计方案:
  方案一:
  方案二:
(3)问题点:

3、代码示例:

(1)代码修改之前

import Foundation

class Person {
    var car: Car?
    
    func refuel(_ gaso: IGasoline) {
        if gaso.isQuality == true {//如果汽油质量过关,我们就给汽车加油
            car?.refuel(gaso)
        }
    }
}

class Car {
    func refuel(_ gaso: IGasoline) {
        print("加\(gaso.name)汽油")
    }
}

protocol IGasoline {
    var name: String { get }
    var isQuality: Bool { get }
}

class Gasoline90: IGasoline {
    var name: String = "90号"
    var isQuality: Bool = false
}

class Gasoline93: IGasoline {
    var name: String = "93号"
    var isQuality: Bool = true
}

可以看到上面有个问题,我们怎么知道汽油的质量是否过关呢,即时我们知道,加油判断油的质量这个事情也不应该由我们来做。

(2)代码修改之后

import Foundation

class Person {//给车加油的人
    var car: Car?
    
    func refuel(_ worker: WorkerInPetrolStation, _ gaso: IGasoline) {
        guard let car = car else {return}
        worker.refuel(car, gaso)
    }
}

class WorkerInPetrolStation {//加油站工作人员
    func refuel(_ car: Car, _ gaso: IGasoline) {
        if gaso.isQuality == true {//如果汽油质量过关,我们就给汽车加油
            car.refuel(gaso)
        }
    }
}

class Car {
    func refuel(_ gaso: IGasoline) {
        print("加\(gaso.name)汽油")
    }
}

protocol IGasoline {
    var name: String { get }
    var isQuality: Bool { get }
}

class Gasoline90: IGasoline {
    var name: String = "90号"
    var isQuality: Bool = false
}

class Gasoline93: IGasoline {
    var name: String = "93号"
    var isQuality: Bool = true
}

可以看到这样我们就实现了低耦合,我们只需要知道有加油站工作人员和要加的汽油就行了,不需要知道太多汽油相关的知识,以及加油相关的操作流程,这些都交给了工作人员,这样是符合我们的迪米特原则的。

七、组合/聚合复用原则

定义:合成/聚合复用原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。它的设计原则是:要尽量使用合成/聚合,尽量不要使用继承。

1、就是说要少用继承,多用合成关系来实现

  继承复用有一定的缺点:比如如果基类发生了改变,那么派生类的的实现就不得不发生改变;而且从超类继承而来的实现是静态的,不可能在运行时发生改变,因此它的灵活性差并最终会限制复用性。而使用组合/聚合复用原则就解决了继承复用的缺点。

2、举例说明:

(1)设计目标:我们实现一个角色,可以是雇员、经理等
(2)设计方案
  方案一:创建三个基类(雇员、经理、学生),角色继承自每个基类的部分属性
  方案二:创建三个基类(雇员、经理、学生)和组合,组合根据需要返回所需不同的功能
(3)问题点:如果只创建一个人,那么这个是没问题的,但是我们一般不可能只用一次,如果多次使用,会多次创建相同多余代码,既不动态也不实用,方案二创建一个新的组合就解决了此类问题,如示例。

3、示例:
image

人被继承到雇员、学生、经理子类其中一种角色。但是实际运用中,雇员、学生和经理分别描述一种角色,而人可以同时有几种不同的角色。比如,一个人既然是经理了就一定是雇员,使用继承来实现角色,则只能使用每一个人具有一种角色,这显然是不合理的。错误的原因就是把角色的等级结构和人的等级结构混淆起来,把Has-A的关系误认为是Is-A的关系,通过下面的改正就可以正确的做到这一点。

image

从上图可以看出,每一个人都可以有一个以上的角色,所以一个人可以同时是雇员又是经理。从这个例子可以看出,当一个类是另一个类的角色时,不应该使用继承描述这种关系。
有了以上设计原则,可以根据设计原则实现很多好的设计模式,下一篇设计模式

参考博客:
https://www.jianshu.com/p/e5c69c7b8c00

相关文章

  • iOS设计模式(三)之抽象工厂模式

    设计模式系列传送门 iOS设计模式(一)之简单工厂模式iOS设计模式(二)之工厂模式iOS设计模式(三)之抽象工厂...

  • iOS设计模式(一)之简单工厂模式

    设计模式系列传送门 iOS设计模式(一)之简单工厂模式iOS设计模式(二)之工厂模式iOS设计模式(三)之抽象工厂...

  • iOS设计模式(二)之工厂模式

    设计模式系列传送门 iOS设计模式(一)之简单工厂模式iOS设计模式(二)之工厂模式iOS设计模式(三)之抽象工厂...

  • 设计模式

    设计原则 IOS设计模式的六大设计原则之开放-关闭原则(OCP,Open-Close Principle) 观察者...

  • iOS设计模式之美-适配器模式

    iOS设计模式之美-工厂模式iOS设计模式之美-抽象工厂模式iOS设计模式之美-生成器模式iOS设计模式之美-适配...

  • iOS设计模式之美-抽象工厂模式

    iOS设计模式之美-工厂模式iOS设计模式之美-抽象工厂模式iOS设计模式之美-生成器模式iOS设计模式之美-适配...

  • iOS设计模式之美-工厂模式

    iOS设计模式之美-工厂模式iOS设计模式之美-抽象工厂模式iOS设计模式之美-生成器模式iOS设计模式之美-适配...

  • iOS设计模式之美-生成器模式

    iOS设计模式之美-工厂模式iOS设计模式之美-抽象工厂模式iOS设计模式之美-生成器模式iOS设计模式之美-适配...

  • 设计模式目录

    1. 设计模式中类的关系和六大设计原则 一、设计模式简介二、设计模式中类的关系三、设计模式的六大设计原则之单一职责...

  • 设计模式之开闭原则

    相关链接:0. 设计模式之六大原则总结1. 设计模式之单一职责原则2. 设计模式之里式替换原则3. 设计模式之依赖...

网友评论

      本文标题:iOS设计(三)1 设计模式之设计原则

      本文链接:https://www.haomeiwen.com/subject/rthuwktx.html