设计模式-模板

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。GoF提出了23种设计模式,本系列将使用Swift语言来实现这些设计模式

概述

模板设计模式是最基础的设计模式之一,在网上被称作模板方法模式,但实际运用时这种设计模式却不仅仅局限于方法。因此笔者对于模板设计模式的理解定义如下:

【模板设计模式】将常见的方法以及对象成员进行封装,创建了一个实现一组抽象方法以及抽象对象成员作为对象实现使用的模板

坏味道的代码

在Swift中有个有趣的数据结构——元组Tuples,现在有这么一段代码。其中传入的每一个元祖表示某个商品的数据类型:

func calculateTax(product: (String, Double, Int)) -> Double {
    return product.1 * 0.17
}

func calculateStockValue(products: [(String, Double, Int)]) -> Double {
    return products.reduce(0.0){
        $0 + $1.1 * Double($1.2)
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    let products = [
        ("Pizazz", 99.8, 10),
        ("Hamburger", 25.6, 8),
        ("Beef", 19.9, 30) ]

    print("The tax of \(products[0].1) is \(calculateTax(product[0]))")
    print("The stock value of all products is \(calculateStockValue(products))")
}

上面的方法通过传入一个或者多个元组用来计算增值税(17%)以及商品存货总额。毫无疑问,对于稍有经验的开发者来说,都能说出这段代码有太大的坏味道了:两个方法过度的依赖于传入的元组结构,这意味着几乎无法复用这些方法

高耦合关系

模板设计模式

在开发语言从面向过程发展到面向对象的过程中,高级语言以及开发框架早已利用各种设计模式进行了封装,我们在不知不觉中享受着这种封装带来的便利却不自知。上方代码中的坏味道主要因为参数类型以及参数值受到限制,为了避免这种坏味道出现,通常使用模板设计模式来解决过高的耦合度。

Swift的模板设计模式

在Swift中,模板设计模式通过使用classstruct两种数据类型作为类对象的创建结构模板,用来创建不同内容的具体对象。因此改变之后的代码如下:

func calculateTax(product: Product) -> Double {
    return product.price * 0.17
}

func calculateStockValue(products: [Product]) -> Double {
    return products.reduce(0){
        return $0 + $1.price * Double($1.stock)
    }
}

class Product {
    var name: String
    var price: Double
    var stock: Int

    init(name: String, price price: Double, stock stock: Int) {
        self.name = name
        self.price = price
        self.stock = stock
    }
}

通过以class结构为模板,我们可以创建各种不同属性的商品。虽然在定义class结构的过程中增加了一些额外的工作,但一来这使得我们的代码更加符合OOP的编程思想,二来解除了方法和元组之间的高度耦合。但这样的代码仍然存在另一个耦合问题——方法和类之间的耦合。如果有一天,项目需要面对全球市场,但是在不同的国家税种不同、税率也不同,这段代码也就有了另外的坏味道。因此我们需要把这两个方法同样放到class结构中成为方法模板

class Product {
    var name: String
    var price: Double
    var stock: Int

    init(name: String, price price: Double, stock stock: Int) {
        self.name = name
        self.price = price
        self.stock = stock
    }

    private func calculateTax() -> Double {
        return price * 0.17
    }

    private func calculateStockValue() -> Double {
        return price * Double(stock)
    }

    func log() {
        print("The tax of \(name) is \(calculateTax())")
        print("The stock value of product is \(calculateStockValue())")
    }
}

class Product_Japan: Product {
    override private calculateTax() -> Double {
        return price * 0.05
    }
}

将方法抽象封装到父类中,并在子类中重写具体实现,这是模板方法模式的典型做法

模板方法模式

为了计算不同地区的税率要实现多个这样的子类的做法带来的代码量也是十分可观的,而且当税率成了一个可改变的因素时,方法可以改变成为接收税率进行计算:

func calculateTax(ratio: Double) -> Double {
    return price * ratio
}

总结

模式优点

  • 将不变的行为抽离封装起来,去除了重复代码
  • 通过子类重写父类实现,可以扩展新的行为

模式缺点

  • classstruct都能利用模板模式来解除高耦合,但两者在传递时采用不同的方式,这容易引发错误
  • 容易造成子类的数量暴增,导致代码设计更加抽象

下一篇:Swift实战-原型模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容

  • TEMPLATE METHOD(模板方法) ———— 类行为型模式 意图 定义一个操作中的算法骨架,而将一些步骤延...
    tomas家的小拨浪鼓阅读 1,125评论 0 2
  • 目录 本文的结构如下: 引言 什么是模板方法模式 模式的结构 代码示例 优点和缺点 适用环境 模式应用 一、引言 ...
    w1992wishes阅读 758评论 0 3
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,592评论 4 59
  • 华夏文化灿, 万世永流传。 有熊居中原, 西陵立西南。 黄帝战夷蛮, 嫘祖开桑田。 狩猎西陵塬, 初会嫘祖面。 霓...
    szx天马行空阅读 214评论 3 1
  • 今天可谓是收获颇多,听了峡山双语学校老师的课后,对我有了很大的启发。在这呢,要善于吸收人家的长处,反思自己的不足。...
    小小鱼儿_4eaf阅读 182评论 2 9