想象一下這種場景,咱們在汽車生產車間,會將汽車生產步驟分作不一樣的流程,提早在車間安裝好,而後,咱們將汽車零部件依次放入流水線,通過不一樣流程處理,最終組裝成一臺汽車。面試
它是將每一個處理流程提早安裝在了流水線上,要想生產汽車,咱們只須要將各類汽車配件放入,就能夠獲得一輛完整的汽車。那麼這種處理過程,咱們就能夠看作是一種隊列模型處理邏輯。apache
接下來,咱們來設定咱們的使用場景。ide
某工廠招工,一大批員工來面試,面試條件有兩個:測試
- 只要男生
- 必須年滿18歲
針對上面的要求,工廠安排了兩場面試,第一場檢查面試者是否爲男生,第二場檢查身份證年齡,是否年滿18歲。this
咱們下面利用代碼隊列來實現這個場景!插件
代碼中會使用到插件lombok,請同窗們自行安裝!code
首先,創建面試者實體類:對象
package cn.wxson.chain.bean; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Setter @Getter @AllArgsConstructor public class User { private String name; private int age; private String gender; }
針對實例類來創建全局上下文,其中包括兩個方法,一個獲取上下文服務;另外一個是交接任務到下一個節點。blog
package cn.wxson.chain.content; import cn.wxson.chain.service.ContextService; /** * Title 全局上下文 * * @author Ason(18078490) * @date 2020-07-28 */ public interface Context<T> { /** * 獲取服務類 * * @return 服務類 */ ContextService<T> service(); /** * 業務邏輯的節點傳遞 * * @param data 數據 */ void transmit(T data); }
爲了保持鏈式結構,咱們須要爲後面的每一個上下文對象提供它的前一個上下文與後一個上下文對象,因此,咱們增長兩個屬性,並實現業務傳遞操做方法:transmit(T data)。繼承
package cn.wxson.chain.content; import lombok.Getter; import lombok.Setter; /** * Title 上下文業務處理抽象類 * 後面的第一個節點上下文、最後一個節點上下文、普通節點上下文都繼承自它 * * @author Ason(18078490) * @date 2020-07-28 */ @Setter @Getter public abstract class AbstractContext<T> implements Context<T> { /** * 前一個上下文 */ private AbstractContext<T> pre; /** * 後一個上下文 */ private AbstractContext<T> next; /** * 業務邏輯的節點傳遞 * * @param data 數據 */ @Override public void transmit(T data) { // 直接進行下個節點的業務操做 this.next.service(data); } /** * 將具體數據業務處理抽象出來,便於節點操做 * * @param data 數據 */ public void service(T data) { this.service().execute(this, data); } }
第一個、最後一個上下文比較特殊,其內部不須要作業務處理,只須要傳遞便可。
package cn.wxson.chain.content.impl; import cn.wxson.chain.content.AbstractContext; import cn.wxson.chain.service.ContextService; /** * Title 第一個節點上下文 * * @author Ason(18078490) * @date 2020-07-28 */ public final class FirstContextImpl<T> extends AbstractContext<T> implements ContextService<T> { /** * 獲取服務類 * * @return 第一個節點返回自身 */ @Override public ContextService<T> service() { return this; } /** * 第一個節點,直接執行下一個節點數據,不作業務處理 * * @param context 上下文 * @param data 數據 */ @Override public void execute(AbstractContext<T> context, T data) { // 不作任何自身業務邏輯處理,直接傳遞給下個節點處理 context.transmit(data); } }
package cn.wxson.chain.content.impl; import cn.wxson.chain.content.AbstractContext; import cn.wxson.chain.service.ContextService; /** * Title 最後一個節點上下文 * * @author Ason(18078490) * @date 2020-07-28 */ public final class LastContextImpl<T> extends AbstractContext<T> implements ContextService<T> { /** * 獲取服務類 * * @return 最後一個節點返回自身 */ @Override public ContextService<T> service() { return this; } /** * 最後一個節點,不作任何處理 * * @param context 上下文 * @param data 數據 */ @Override public void execute(AbstractContext<T> context, T data) { // 不作任何業務處理,也不須要再傳遞下去 // NOOP } }
package cn.wxson.chain.content.impl; import cn.wxson.chain.content.AbstractContext; import cn.wxson.chain.service.ContextService; /** * Title 普通節點的上下文 * * @author Ason(18078490) * @date 2020-07-28 */ public class CommonContextImpl<T> extends AbstractContext<T> { /** * 具體業務實現服務類 */ private ContextService<T> service; /** * 無參構造 */ public CommonContextImpl() { super(); } /** * 帶參構造 * * @param service 服務類 */ public CommonContextImpl(ContextService<T> service) { this.service = service; } /** * 獲取服務類 * * @return 返回傳進來的服務類 */ @Override public ContextService<T> service() { return this.service; } }
只包含一個具體業務處理方法:
package cn.wxson.chain.service; import cn.wxson.chain.content.AbstractContext; /** * Title 上下文業務服務類 * * @author Ason(18078490) * @date 2020-07-28 */ public interface ContextService<T> { /** * 業務邏輯處理 * * @param context 上下文 * @param data 數據 */ void execute(AbstractContext<T> context, T data); }
第一個節點上下文與最後一個節點上下文已在FirstContextImpl.class和LastContextImpl.class中實現,處理邏輯可參考代碼說明。普通節點的上下文處理邏輯咱們抽象出一個靜態類,作業務剝離,將具體業務轉移到節點實現類中去,這裏只作抽象業務處理和節點傳遞。
package cn.wxson.chain.service; import cn.wxson.chain.content.AbstractContext; /** * Title 默認上下文業務服務類 * * @author Ason(18078490) * @date 2020-07-28 */ public abstract class AbstractDefaultContextService<T> implements ContextService<T> { /** * 業務邏輯處理 * * @param context 上下文 * @param data 數據 */ @Override public void execute(AbstractContext<T> context, T data) { // 1.本節點的業務邏輯處理 this.execute(data); // 2.傳遞邏輯到下個節點 context.transmit(data); } /** * 本節點的業務邏輯處理 * * @param data 數據 */ public abstract void execute(T data); }
針對年齡和性別兩場面試,咱們分別實現業務處理:
package cn.wxson.chain.service.impl; import cn.wxson.chain.bean.User; import cn.wxson.chain.service.AbstractDefaultContextService; import lombok.extern.slf4j.Slf4j; /** * Title 年齡說明 * * @author Ason(18078490) * @date 2020-07-28 */ @Slf4j public class AgeServiceImpl extends AbstractDefaultContextService<User> { /** * 根據人員年齡進行檢查 * 必須成年,大於等於18歲 * * @param user 數據 */ @Override public void execute(User user) { String rs = user.getAge() >= 18 ? "合格" : "不合格"; log.info("人員姓名:{},年齡檢查結果:{}", user.getName(), rs); } }
package cn.wxson.chain.service.impl; import cn.wxson.chain.bean.User; import cn.wxson.chain.service.AbstractDefaultContextService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; /** * Title 姓名說明 * * @author Ason(18078490) * @date 2020-07-28 */ @Slf4j public class GenderServiceImpl extends AbstractDefaultContextService<User> { /** * 根據人員性別進行檢查 * 只要男性 * * @param user 數據 */ @Override public void execute(User user) { String rs = StringUtils.equals(user.getGender(), "男") ? "合格" : "不合格"; log.info("人員姓名:{},姓名檢查結果:{}", user.getName(), rs); } }
經過以上步驟,咱們就實現了具體業務的處理邏輯,接下來,咱們將業務採用隊列形式操做。
package cn.wxson.chain; import cn.wxson.chain.content.AbstractContext; import cn.wxson.chain.content.impl.CommonContextImpl; import cn.wxson.chain.content.impl.FirstContextImpl; import cn.wxson.chain.content.impl.LastContextImpl; import cn.wxson.chain.service.ContextService; /** * Title 上下文隊列 * * @author Ason(18078490) * @date 2020-07-28 */ public class Pipeline<T> { /** * 第一個上下文 */ private final AbstractContext<T> first; /** * 最後一個上下文 */ private final AbstractContext<T> last; /** * 初始化隊列第一個上下文與最後一個上下文,並將它們連起來 */ public Pipeline() { this.first = new FirstContextImpl<T>(); this.last = new LastContextImpl<T>(); this.first.setNext(this.last); this.last.setPre(this.first); } /** * 新增服務類做爲普通上下文節點包裝 * 並把它排到最後一個上下文前面,即:普通節點的隊尾 * * @param service 服務類 */ public void add(ContextService<T> service) { AbstractContext<T> context = new CommonContextImpl<T>(service); AbstractContext<T> backwardsSecond = this.last.getPre(); context.setPre(backwardsSecond); context.setNext(this.last); backwardsSecond.setNext(context); this.last.setPre(context); } /** * 新增服務類做爲普通上下文節點包裝 * 並把它排到第一個上下文後面,即:普通節點的隊首 * * @param service 服務類 */ public void addFirst(ContextService<T> service) { AbstractContext<T> context = new CommonContextImpl<T>(service); AbstractContext<T> forwardsSecond = this.first.getNext(); this.first.setNext(context); forwardsSecond.setPre(context); context.setPre(this.first); context.setNext(forwardsSecond); } /** * 從隊列第一個上下文節點開始處理數據 * * @param data 數據 */ public void handler(T data) { this.first.transmit(data); } }
這樣,咱們就針對工廠的兩場面試準備工做都作好了,接下來測試一下。
package cn.wxson.chain; import cn.wxson.chain.bean.User; import cn.wxson.chain.service.ContextService; import cn.wxson.chain.service.impl.AgeServiceImpl; import cn.wxson.chain.service.impl.GenderServiceImpl; /** * Title 測試類 * * @author Ason(18078490) * @date 2020-07-28 */ public class Domain { public static void main(String[] arg) { // 建立預處理隊列 Pipeline<User> pipeline = new Pipeline<User>(); ContextService<User> nameService = new GenderServiceImpl(); ContextService<User> ageService = new AgeServiceImpl(); pipeline.add(nameService); pipeline.add(ageService); // 放入人員信息,逐個檢查 pipeline.handler(new User("張三", 18, "男")); pipeline.handler(new User("李四", 20, "女")); pipeline.handler(new User("王五", 13, "男")); } }
運行結果:
經過這個例子能夠看到,咱們提早將面試流程安排好,只須要讓面試者逐個進入,就能夠達到逐個檢查的流水線效果,實現人員是否知足面試邀請的考覈工做!