持续创作,加速成长!这是我参与「掘金日新计划 · 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] = [
"&" : "&",
"'": "'",
">": ">",
"<": "<",
""": """
]
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))")
输出结果:
过滤前的内容: ["有人出售黄色书:<黄青味道>", "有人企图搞反动活动,————“造谣咨询”"]
过滤后的内容:["有人出售书:<黄青味道>", "有人企图搞活动,————“造谣咨询”"]
结语
过滤器模式在移动端开发过程中,用的还是比较少的,不过多了解一下也不是坏事。
扩展阅读 下面还有其他模式