想象一下这种场景,咱们在汽车生产车间,会将汽车生产步骤分作不一样的流程,提早在车间安装好,而后,咱们将汽车零部件依次放入流水线,通过不一样流程处理,最终组装成一台汽车。面试
它是将每一个处理流程提早安装在了流水线上,要想生产汽车,咱们只须要将各类汽车配件放入,就能够获得一辆完整的汽车。那么这种处理过程,咱们就能够看作是一种队列模型处理逻辑。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, "男")); } }
运行结果:
经过这个例子能够看到,咱们提早将面试流程安排好,只须要让面试者逐个进入,就能够达到逐个检查的流水线效果,实现人员是否知足面试邀请的考核工做!