聊聊Swift中的设计模式---结构型(过滤器模式)

196 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情


前言

在面向对象的开发过程中,其实咱们或多或少的都接触过一些设计模式,可能知道或不知道其对应的名称,也不知道其具体使用场景,今天咱们就来说说几种常见的设计模式,帮助你们在开发过程中,更加得心应手。

正文

过滤器模式

过滤器模式用简单的话来讲,就是使用自定义的标准来过滤一组想要筛选的对象,通过逻辑运算以解耦的方式把它们连接起来。

用生活中的例子来说:比如电信推出某项优惠套餐,但是套餐可使用的用户群体有限,必须满足入网 3 年以上这种条件,我们可以将 “入网三年” 作为客户群体的过滤条件.这样,就可以将非3年以上的客户筛选出来。

过滤器模式的角色:

  • 抽象过滤器角色(AbstractFilter):负责定义过滤器的实现接口,具体的实现还要具体过滤器角色去参与,客户端可以调用抽象过滤器角色中定义好的方法,将客户端的所有请求委派到具体的实现类去,从而让实现类去处理;
  • 具体过滤器角色(ConcreteFilter):该角色负责具体筛选规则的逻辑实现,最后再返回一个过滤后的数据集合,标准的过滤器只对数据做过滤,当然也可以对集合中的数据做某项处理,再将处理后的集合返回;
  • 被过滤的主体角色(Subject):一个软件系统中可以有一个或多个目标角色,在具体过滤器角色中会对指定感兴趣的目标进行处理,以确保后面的数据确实是我想要的。

下面,咱们来通过过滤敏感词汇和HTML标签这个例子来说明一下。

先定义一个过滤器接口

import Foundation

/// 过滤器接口
protocol Filter {
    associatedtype T
    func filter(items: [T]) -> [T]
}

这个过滤器接口就是抽象的过滤器角色

然后定义过滤器链,它可以包含多个过滤器,并管理这些过滤器


class FilterChain<F> where F: Filter {

    private var filters: [F] = []

    init() {}

    func addFilter(_ filter: F) {
        self.filters.append(filter)
    }

    func filter(items: [F.T]) -> [F.T] {
        var items: [F.T] = items
        for filter in filters {
            items = filter.filter(items: items)
        }
        return items
    }
}

定义一个对string类型的过滤器,这个是对Filter过滤器抽象类的实现,它定义了T这个类型是string,当然,也可以定义一个其他类型的过滤器。


class StringFilter: Filter {
    typealias T = String
    func filter(items: [String]) -> [String] {
        return items
    }
}


接下来分别定义『敏感词汇过滤』和『HTML标签过滤』的过滤器。


/// 敏感词汇过滤
class SensitiveFilter: StringFilter {

    private var sensitives: [String] = ["黄色", "反动", "贪污"]

    override func filter(items: [String]) -> [String] {
        var result: [String] = []
        // 对每个元素进行过滤
        for ele in items {
            var str = ele
            self.sensitives.forEach { (sen) in
                if str.contains(sen) {
                    str = str.replacingOccurrences(of: sen, with: "")
                }
            }
            result.append(str)
        }
        return result
    }

}

class HtmlFilter: StringFilter {

    private let wordMap: [String: String] = [
        "&" : "&amp;",
        "'": "&apos;",
        ">": "&gt;",
        "<": "&lt;",
        """: "&quot;"
    ]

    override func filter(items: [String]) -> [String] {
        var result: [String] = []

        for ele in items {
            var str = ele
            self.wordMap.forEach { (key, value) in
                str = str.replacingOccurrences(of: key, with: value)
            }
            result.append(str)
        }
        return result
    }

}

最后写一个String类型的扩展,方便调用。


extension String {
    subscript(_ indexs: Range<Int>) -> String {
        let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
        let endIndex = index(startIndex, offsetBy: indexs.upperBound)
        return String(self[beginIndex..<endIndex])
    }
}

我们来看看怎么效果怎么样

let contents = [
    "有人出售黄色书:<黄青味道>",
    "有人企图搞反动活动,————“造谣咨询”"
]

print("过滤前的内容: (contents)")

let filterChain = FilterChain<StringFilter>()
filterChain.addFilter(SensitiveFilter())
filterChain.addFilter(HtmlFilter())

print("过滤后的内容:(filterChain.filter(items: contents))")

输出结果:

过滤前的内容: ["有人出售黄色书:<黄青味道>", "有人企图搞反动活动,————“造谣咨询”"]

过滤后的内容:["有人出售书:&lt;黄青味道&gt;", "有人企图搞活动,————“造谣咨询”"]

结语

过滤器模式在移动端开发过程中,用的还是比较少的,不过多了解一下也不是坏事。


扩展阅读 下面还有其他模式

创建型-工厂模式

创建型-建造者模式

结构型-适配器模式

结构型-桥接模式

结构型-组合模式