责任链模式
https://www.tuicool.com/articles/yINJVv
Decoupling is one of the prominent mantras in software engineering. Chain of responsibility helps to decouple sender of a request and receiver of the request with some trade-offs. Chain of responsibility is a design pattern where a sender sends a request to a chain of objects, where the objects in the chain decide themselves who to honor the request. If an object in the chain decides not to serve the request, it forwards the request to the next object in the chain.
Responsibility is outsourced. In a chain of objects, the responsibility of deciding who to serve the request is left to the objects participating in the chains. It is similar to ‘passing the question in a quiz scenario’. When the quiz master asks a question to a person, if he doesn’t knows the answer, he passes the question to next person and so on. When one person answers the question, the passing flow stops. Sometimes, the passing might reach the last person and still nobody gives the answer.
Welcome to behavioral design patterns. This is the first tutorial in behavioral category of our famous design pattern series.
Highlights of Chain of Responsibility
- Sender will not know which object in the chain will serve its request.
- Every node in chain will have the responsibility to decide, if they can serve the request.
- If node decides to forward the request, it should be capable of choosing the next node and forward it.
- There is a possibility where none of the node may serve the request.
Pipeline模式
https://en.wikipedia.org/wiki/Pipeline_%28software%29
In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline. Usually some amount of buffering is provided between consecutive elements. The information that flows in these pipelines is often a stream of records, bytes or bits, and the elements of a pipeline may be called filters; this is also called the pipes and filters design pattern. Connecting elements into a pipeline is analogous to function composition.
责任链实例-Nginx filter模块
https://www.evanmiller.org/nginx-modules-guide.html
4.3. Filter Installation
Filters are installed in the post-configuration step. We install both header filters and body filters in the same place.
Let’s take a look at the chunked filter module for a simple example. Its module context looks like this:
static ngx_http_module_t ngx_http_chunked_filter_module_ctx = { NULL, /* preconfiguration */ ngx_http_chunked_filter_init, /* postconfiguration */ ... };
Here’s what happens in
ngx_http_chunked_filter_init
:static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf) { ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_chunked_header_filter; ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_chunked_body_filter; return NGX_OK; }
What’s going on here? Well, if you remember, filters are set up with a CHAIN OF RESPONSIBILITY. When a handler generates a response, it calls two functions:
ngx_http_output_filter
, which calls the global function referencengx_http_top_body_filter
; andngx_http_send_header
, which calls the global function referencengx_http_top_header_filter
.
ngx_http_top_body_filter
andngx_http_top_header_filter
are the respective "heads" of the body and header filter chains. Each "link" on the chain keeps a function reference to the next link in the chain (the references are calledngx_http_next_body_filter
andngx_http_next_header_filter
). When a filter is finished executing, it just calls the next filter, until a specially defined "write" filter is called, which wraps up the HTTP response. What you see in this filter_init function is the module adding itself to the filter chains; it keeps a reference to the old "top" filters in its own "next" variables and declares its functions to be the new "top" filters. (Thus, the last filter to be installed is the first to be executed.)
责任链实例-spring拦截器
http://www.cnblogs.com/xiepeixing/p/4262540.html
类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.
常用场景:
1、日志记录:
记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:
如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:
有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:
读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:
如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。
package org.springframework.web.servlet; public interface HandlerInterceptor { boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现);
返回值:true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
责任链实例--Nodejs-express路由器
http://expressjs.com/zh-cn/guide/routing.html
路由方法
路由方法派生自 HTTP 方法之一,附加到
express
类的实例。以下代码是为访问应用程序根目录的 GET 和 POST 方法定义的路由示例。
// GET method route app.get('/', function (req, res) { res.send('GET request to the homepage'); }); // POST method route app.post('/', function (req, res) { res.send('POST request to the homepage'); });
Pipeline模式 -- Nodejs-express中间件
http://www.expressjs.com.cn/guide/using-middleware.html
router-level middleware
Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of
express.Router()
.
var router = express.Router()
Load router-level middleware by using the
router.use()
androuter.METHOD()
functions.The following example code replicates the middleware system that is shown above for application-level middleware, by using router-level middleware:
var app = express() var router = express.Router() // a middleware function with no mount path. This code is executed for every request to the router router.use(function (req, res, next) { console.log('Time:', Date.now()) next() }) // a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path router.use('/user/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl) next() }, function (req, res, next) { console.log('Request Type:', req.method) next() }) // a middleware sub-stack that handles GET requests to the /user/:id path router.get('/user/:id', function (req, res, next) { // if the user ID is 0, skip to the next router if (req.params.id === '0') next('route') // otherwise pass control to the next middleware function in this stack else next() }, function (req, res, next) { // render a regular page res.render('regular') }) // handler for the /user/:id path, which renders a special page router.get('/user/:id', function (req, res, next) { console.log(req.params.id) res.render('special') }) // mount the router on the app app.use('/', router)
Pipeline模式 -- JQuery链式写法
https://www.jquery-tutorial.net/introduction/method-chaining/
<div id="divTest2"></div> <script type="text/javascript"> $("#divTest2").text("Hello, world!") .removeClass("blue") .addClass("bold") .css("color", "blue"); </script>