mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
758 lines
24 KiB
HTML
758 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
<body>
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/00 生活中的设计模式:启程之前,请不要错过我.md.html">00 生活中的设计模式:启程之前,请不要错过我.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/01 监听模式:坑爹的热水器.md.html">01 监听模式:坑爹的热水器.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/02 适配模式:身高不够鞋来凑.md.html">02 适配模式:身高不够鞋来凑.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/03 状态模式:人与水的三态.md.html">03 状态模式:人与水的三态.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/04 单例模式:你是我生命的唯一.md.html">04 单例模式:你是我生命的唯一.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/05 职责模式:我的假条去哪了.md.html">05 职责模式:我的假条去哪了.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/06 中介模式:找房子问中介.md.html">06 中介模式:找房子问中介.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/07 代理模式:帮我拿一下快递.md.html">07 代理模式:帮我拿一下快递.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/08 装饰模式:你想怎么穿就怎么穿.md.html">08 装饰模式:你想怎么穿就怎么穿.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/09 工厂模式:你要拿铁还是摩卡.md.html">09 工厂模式:你要拿铁还是摩卡.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/10 迭代模式:下一个就是你了.md.html">10 迭代模式:下一个就是你了.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/11 组合模式:自己组装电脑.md.html">11 组合模式:自己组装电脑.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/12 构建模式:想要车还是庄园.md.html">12 构建模式:想要车还是庄园.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/13 克隆模式:给你一个分身术.md.html">13 克隆模式:给你一个分身术.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/14 策略模式:怎么来不重要,人到就行.md.html">14 策略模式:怎么来不重要,人到就行.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/15 命令模式:大闸蟹,走起!.md.html">15 命令模式:大闸蟹,走起!.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/16 备忘模式:好记性不如烂笔头.md.html">16 备忘模式:好记性不如烂笔头.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/17 享元模式:颜料很贵必须充分利用.md.html">17 享元模式:颜料很贵必须充分利用.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/18 外观模式:学妹别慌,学长帮你.md.html">18 外观模式:学妹别慌,学长帮你.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/19 访问模式:一千个读者一千个哈姆雷特.md.html">19 访问模式:一千个读者一千个哈姆雷特.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/20 生活中的设计模式:与经典设计模式的不解渊源.md.html">20 生活中的设计模式:与经典设计模式的不解渊源.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/21 生活中的设计模式:那些未完待续的设计模式.md.html">21 生活中的设计模式:那些未完待续的设计模式.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="current-tab" href="/专栏/白话设计模式 28 讲(完)/22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html">22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html</a>
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/23 深入解读对象池技术:共享让生活更便捷.md.html">23 深入解读对象池技术:共享让生活更便捷.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/24 深入解读回调机制:把你技能亮出来.md.html">24 深入解读回调机制:把你技能亮出来.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/25 谈谈我对设计模式的理解.md.html">25 谈谈我对设计模式的理解.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/26 谈谈我对设计原则的思考.md.html">26 谈谈我对设计原则的思考.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/27 谈谈我对项目重构的看法.md.html">27 谈谈我对项目重构的看法.md.html</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
</script>
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆</h1>
|
||
|
||
<p>故事剧情】</p>
|
||
|
||
<blockquote>
|
||
|
||
<p>腊八已过,粥已喝,马上就要过年了!别人家的公司现在都是开年会、发现金红包、发 iPone、发平衡车什么的,而 Tony 什么也没有,只能默默地躲在朋友圈的角落里,好在最后一周还算发了一个慰问品——九阳豆浆机。</p>
|
||
|
||
<p>豆浆机已经有了,怎么制作一杯鲜纯细腻的豆浆呢?Tony 在网上找了一些资料,摸索了半天总算学会了,准备周末买一些大豆,自制早餐!</p>
|
||
|
||
<p>把浸泡过的大豆放进机器,再加入半壶水,然后选择模式并按下“启动”键,15 分钟后就可以了,但这并没有完,因为还有最关键的一步,那就是往杯子倒豆浆的时候要用过滤网把豆渣过虑掉。这样,一杯美味的阳光早餐就出来了。</p>
|
||
|
||
</blockquote>
|
||
|
||
<p><img src="assets/1b943e50-8e53-11e8-80d1-2d51ff7e1c55.jpg" alt="img" /></p>
|
||
|
||
<h3>用程序来模拟生活</h3>
|
||
|
||
<p>世间万物,唯有爱与美食不可辜负,吃的健康才能活的出彩。在上面制作豆浆的过程中,豆浆机很重要,但过滤网更关键,因为它直接影响了豆桨的质量。下面我们用程序来模拟一下这关键的步骤。</p>
|
||
|
||
<p>源码示例:</p>
|
||
|
||
<pre><code class="language-python">class FilterScreen:
|
||
|
||
"""过滤网"""
|
||
def doFilter(self, rawMaterials):
|
||
|
||
for material in rawMaterials:
|
||
|
||
if (material == "豆渣"):
|
||
|
||
rawMaterials.remove(material)
|
||
|
||
return rawMaterials
|
||
</code></pre>
|
||
|
||
<p>测试代码:</p>
|
||
|
||
<pre><code class="language-python">def testFilterScreen():
|
||
|
||
rawMaterials = ["豆浆", "豆渣"]
|
||
|
||
print("过滤前:", rawMaterials)
|
||
|
||
filter = FilterScreen()
|
||
|
||
filteredMaterials = filter.doFilter(rawMaterials)
|
||
|
||
print("过滤后:", filteredMaterials)
|
||
</code></pre>
|
||
|
||
<p>输出结果:</p>
|
||
|
||
<pre><code>过滤前: ['豆浆', '豆渣']
|
||
|
||
过滤后: ['豆浆']
|
||
</code></pre>
|
||
|
||
<h3>从剧情中思考过滤器模式</h3>
|
||
|
||
<p>在上面的示例中,豆浆机中有豆浆和豆渣,往杯子里倒的过程中,用过滤网把豆渣过滤掉才能获得更加鲜嫩细腻的豆浆。过滤网起着一个过滤的作用,在程序中也有一种类似的机制,叫<strong>过滤器模式</strong>。</p>
|
||
|
||
<h4>过滤器模式</h4>
|
||
|
||
<blockquote>
|
||
|
||
<p>过滤器模式就是将一组对象,根据某种规则,过滤掉一些不符合要求的对象的过程。</p>
|
||
|
||
</blockquote>
|
||
|
||
<p>如在互联网上发布信息时敏感词汇的过滤,在 Web 接口的请求与响应时,对请求和响应信息的过滤。过滤器模式的核心思想非常简单:就是把不需要的信息过滤掉,怎么判定哪些是不需要的信息呢?这就需要制定规则。过滤的过程如下图:</p>
|
||
|
||
<p><img src="assets/3e919c40-8e53-11e8-80d1-2d51ff7e1c55.jpg" alt="enter image description here" /></p>
|
||
|
||
<p>举一更加形象的例子,在基建行业中,沙子是最重要的原材料之一,这些沙子很多是从江河中打捞上来的,而打捞上来的不只有沙子,还有小石头和水。若要得到这些颗粒均匀的沙子,就必须把水和石头过滤掉。</p>
|
||
|
||
<h4>与职责模式的联系</h4>
|
||
|
||
<p>在《[生活中的职责模式——我的假条去哪了]》一文中,我们讲了职责模式(也就是责任链模式)。过滤器与责任链的相似之处是处理过程都是一环一环地进行,不同之处在于责任链中责任的传递一般会有一定的顺序,而过滤器通常没有这种顺序,所以过滤器会比责任链还简单。</p>
|
||
|
||
<h3>过滤器模式的模型抽象</h3>
|
||
|
||
<p>一些熟悉 Python 的读者可能会觉得上面示例中的这种写法太麻烦了,Python 本身就自带了 filter() 函数。用下面这段代码就能轻松搞定,结果是一样的,但代码少了好几行:</p>
|
||
|
||
<pre><code class="language-python">def testFilter():
|
||
|
||
rawMaterials = ["豆浆", "豆渣"]
|
||
|
||
print("过滤前:", rawMaterials)
|
||
|
||
filteredMaterials = list(filter(isSoybeanMilk, rawMaterials))
|
||
|
||
print("过滤后:", filteredMaterials)
|
||
def isSoybeanMilk(material):
|
||
|
||
return material == "豆浆"
|
||
</code></pre>
|
||
|
||
<p>能提出这个问题,说明你是带思考阅读本文的。之所以要这么写,有以下两个原因:</p>
|
||
|
||
<ul>
|
||
|
||
<li>Python 自带的 filter() 是函数式编程(即面向过程式的编程),而设计模式讲述的是一种面向对象的设计思想。</li>
|
||
|
||
<li>filter() 函数只是进行简单的数组中对象的过滤,对于一些更复杂的需求(如对不符合要求的对象,不是过滤掉而是进行替换),filter() 函数是难以应付的。</li>
|
||
|
||
</ul>
|
||
|
||
<h4>代码框架</h4>
|
||
|
||
<p>基于上面这些问题的思考,我们可以对过滤器模式进行进一步的重构和优化,抽象出过滤器模式的框架模型。</p>
|
||
|
||
<pre><code class="language-python">from abc import ABCMeta, abstractmethod
|
||
|
||
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
|
||
class Filter(metaclass=ABCMeta):
|
||
|
||
"""过滤器"""
|
||
@abstractmethod
|
||
|
||
def doFilter(self, elements):
|
||
|
||
"""过滤方法"""
|
||
|
||
pass
|
||
class FilterChain(Filter):
|
||
|
||
"过滤器链"
|
||
def __init__(self):
|
||
|
||
self._filters = []
|
||
def addFilter(self, filter):
|
||
|
||
self._filters.append(filter)
|
||
def removeFilter(self, filter):
|
||
|
||
self._filters.remove(filter)
|
||
def doFilter(self, elements):
|
||
|
||
for filter in self._filters:
|
||
|
||
filter.doFilter(elements)
|
||
</code></pre>
|
||
|
||
<h4>类图</h4>
|
||
|
||
<p>上面的代码框架可用类图表示如下:</p>
|
||
|
||
<p><img src="assets/4cd24ac0-8e53-11e8-9cd7-51dfc6c66063.jpg" alt="enter image description here" /></p>
|
||
|
||
<p>Filter 是所有过滤器的抽象类,定义了统一的过滤接口 doFilter()。FilterA 和 FilterB 是具体的过滤器类,一个类定义一个过滤规则。FilterChain 是一个过滤器链,它可以包含多个过滤器,并管理这些过滤器,在过滤对象元素时,包含的每一个过滤器都会进行一次过滤。</p>
|
||
|
||
<h4>基于框架的实现</h4>
|
||
|
||
<p>有了上面的代码框架之后,我们要实现示例代码的功能就会更简单明确了。最开始的示例代码假设它为 version 1.0,那么再看看基于框架的 version 2.0 吧。</p>
|
||
|
||
<pre><code class="language-python">class FilterScreen(Filter):
|
||
|
||
"""过滤网"""
|
||
def doFilter(self, elements):
|
||
|
||
for material in elements:
|
||
|
||
if (material == "豆渣"):
|
||
|
||
elements.remove(material)
|
||
|
||
return elements
|
||
</code></pre>
|
||
|
||
<p>测试代码不用变。自己跑一下,会发现输出结果和之前的是一样的。</p>
|
||
|
||
<h4>模型说明</h4>
|
||
|
||
<h5>设计要点</h5>
|
||
|
||
<p>过滤器模式中主要有三个角色,在设计过滤器模式时要找到并区分这些角色:</p>
|
||
|
||
<ul>
|
||
|
||
<li><strong>过滤的目标(Target):</strong> 即要被过滤的对象,通常是一个对象数组(对象列表)。</li>
|
||
|
||
<li><strong>过滤器(Filter):</strong> 负责过滤不需要的对象,一般一个规则对应一个类。</li>
|
||
|
||
<li><strong>过滤器链(FilterChain):</strong> 即过滤器的集合,负责管理和维护过滤器,用这个对象进行过滤时,它包含的每一个子过滤器都会进行一次过滤。这个类并不总是需要的,但如果有多个过滤器,有这个类将会带来极大的方便。</li>
|
||
|
||
</ul>
|
||
|
||
<h4>优缺点</h4>
|
||
|
||
<p>优点:</p>
|
||
|
||
<ul>
|
||
|
||
<li>将对象的过滤、校验逻辑抽离出来,降低系统的复杂度。</li>
|
||
|
||
<li>过滤规则可实现重复利用。</li>
|
||
|
||
</ul>
|
||
|
||
<p>缺点:性能较低,每个过滤器都会对每一个元素进行遍历。如果有 n 个元素、m 个过滤器,则复杂度为 O(mn)。</p>
|
||
|
||
<h3>实战应用</h3>
|
||
|
||
<p>我们在互联网上发布信息时,经常被进行敏感词的过滤;在表单提交的信息要以 HTML 的形式进行显示,会对一些特殊字符的进行转换。这时,我们就需要用过滤器模式对提交的信息进行过滤和处理。</p>
|
||
|
||
<p><strong>源码示例:</strong></p>
|
||
|
||
<pre><code class="language-python">import re
|
||
|
||
# 引入正则表达式库
|
||
class SensitiveFilter(Filter):
|
||
|
||
"""敏感词过滤"""
|
||
def __init__(self):
|
||
|
||
self.__sensitives = ["黄色", "台独", "贪污"]
|
||
def doFilter(self, elements):
|
||
|
||
# 敏感词列表转换成正则表达式
|
||
|
||
regex = ""
|
||
|
||
for word in self.__sensitives:
|
||
|
||
regex += word + "|"
|
||
|
||
regex = regex[0: len(regex) - 1]
|
||
# 对每个元素进行过滤
|
||
|
||
newElements = []
|
||
|
||
for element in elements:
|
||
|
||
item, num = re.subn(regex, "", element)
|
||
|
||
newElements.append(item)
|
||
return newElements
|
||
class HtmlFilter(Filter):
|
||
|
||
"HTML特殊字符转换"
|
||
def __init__(self):
|
||
|
||
self.__wordMap = {
|
||
|
||
"&": "&amp;",
|
||
|
||
"'": " &apos;",
|
||
|
||
">": "&gt;",
|
||
|
||
"<": "&lt;",
|
||
|
||
"\"": " &quot;",
|
||
|
||
}
|
||
def doFilter(self, elements):
|
||
|
||
newElements = []
|
||
|
||
for element in elements:
|
||
|
||
for key, value in self.__wordMap.items():
|
||
|
||
element = element.replace(key, value)
|
||
|
||
newElements.append(element)
|
||
|
||
return newElements
|
||
</code></pre>
|
||
|
||
<p><strong>测试代码:</strong></p>
|
||
|
||
<pre><code class="language-python">def testFiltercontent():
|
||
|
||
contents = [
|
||
|
||
'有人出售黄色书:<黄情味道>',
|
||
|
||
'有人企图搞台独活动, ——"造谣咨询"',
|
||
|
||
]
|
||
|
||
print("过滤前的内容:", contents)
|
||
|
||
filterChain = FilterChain()
|
||
|
||
filterChain.addFilter(SensitiveFilter())
|
||
|
||
filterChain.addFilter(HtmlFilter())
|
||
|
||
newContents = filterChain.doFilter(contents)
|
||
|
||
print("过滤后的内容:", newContents)
|
||
</code></pre>
|
||
|
||
<p><strong>输出结果:</strong></p>
|
||
|
||
<pre><code>过滤前的内容: ['有人出售黄色书:<黄情味道>', '有人企图搞台独活动, ——"造谣咨询"']
|
||
|
||
过滤后的内容: ['有人出售书:&lt;黄情味道&gt;', '有人企图搞活动, —— &quot;造谣咨询 &quot;']
|
||
</code></pre>
|
||
|
||
<h3>应用场景</h3>
|
||
|
||
<ul>
|
||
|
||
<li>敏感词过滤、舆情监测。</li>
|
||
|
||
<li>需要对对象列表(或数据列表)进行检验、审查或预处理的场景。</li>
|
||
|
||
<li>对网络接口的请求和响应进行拦截,如对每一个请求和响应记录日志,以便日后分析。</li>
|
||
|
||
</ul>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/21 生活中的设计模式:那些未完待续的设计模式.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/23 深入解读对象池技术:共享让生活更便捷.md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997bacecde3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
</script>
|
||
</html>
|
||
|