访问者模式

访问者模式

1.说明

同一个事物的不同视角下访问信息的不同

家长视角下的老师-》教学质量怎么样
家长视角下的学生-》分数好不好

校长视角下的老师-》老没有被投诉
校长视角下的学生-》是不是三好学生

2.抽象代码结构

2.1 抽象角色,老师,学生

User.java

@NoArgsConstructor
@AllArgsConstructor
@Data
public abstract class User {
    protected String name; // 姓名
    protected String identity; // 身份
    protected String clazz; // 班级

    public abstract void accept(Visitor visitor);
}

Student.java

@Data
@NoArgsConstructor
public class Student extends User{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

Teacher.java

@NoArgsConstructor
@Data
public class Teacher extends User{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

2.2 角色的说明

identity:老师角色是普通教师,特级教师;学生是重点班还是普通班
clazz:班级
核心是accept的抽象方法里参数是视角Visitor对象。并且角色实现方法里,把自身传递进去

2.3 视角的定义

Visitor.java

public interface Visitor {
    void visit(Student student);

    void visit(Teacher teacher);
}

定义了重载方法,入参类型不一致。这个是关键

家长视图ParentVisitor.java

@Slf4j
public class ParentVisitor implements Visitor{

    public void visit(Student student) {
        log.info("student visit ...");
    }

    @Override
    public void visit(Teacher teacher) {
        log.info("teacher visit ...");
    }
}

3.测试类说明

ViewMain.java

public class ViewMain {
    public static void main(String[] args) {
        Visitor visitor = new ParentVisitor(); // 定义家长视角
        Student student = new Student();
        student.setName("hby");
        student.setClazz("三年二班");
        student.setIdentity("重点班");
        student.accept(visitor); // 学生调用accept把视角传递进去
    }
}

4.优缺点

优点:工程结构更容易添加和修改。做到了系统服务的解耦,代码更清晰

缺点:抽象类的抽象方法时候还需要接受访问者接口的参数传递。该设计会让代码变得组织难度加大。违背了米特原则。最少知道原则。
一定要符合场景的运用,以及提取这部分设计思想的精髓才是重中之重。

5.访问者生产例子

用于切面中记录各种操作的操作日志
属于访问者模式的变种
Visitor.java

public interface Visitor {

    List<History> visit(String user, String nickName, OperationType operationType, Object[] args, Object resp);

}

BaseVisitor.java

public abstract class BaseVisitor implements Visitor {

}

CreateVisitor.java

public class CreateVistor extends BaseVisitor{


    private TicketMapper ticketMapper;

    public CreateVistor() {
        ticketMapper = BeanContext.getBean(TicketMapper.class);
    }

    @Override
    public List<History> visit(String user, String nickName, OperationType operationType, Object[] args, Object resp) {
        StringBuilder msg = new StringBuilder();
        msg.append(nickName).append("(").append(user).append(") ");
        msg.append("创建了任务");
        Long tickId = JsonUtils.toJson(resp).get(Constants.DATA_LIST).getAsLong();

        Ticket t = ticketMapper.selectById(tickId);
        String assignee = t.getAssignee();
        String assigneeCn = t.getAssigneeCn();

        msg.append(",任务受理人为");

        String assignTxt = assigneeCn+"("+assignee+")";
        if(assigneeCn==null){
            assignTxt = assignee;
        }
        msg.append(assignTxt);

        return Lists.newArrayList(History.builder()
                .ticketId(tickId)
                .user(user)
                .operation(operationType)
                .msg(msg.toString())
                .createTime(new Date()).build());
    }
}

切面类

@Aspect
@Component
public class OperationHisAspect {

    private static final Logger logger = LoggerFactory.getLogger(OperationHisAspect.class);


    @Resource
    private HistoryMapper historyMapper;

    private Map<OperationType, BaseVisitor> visitorMap;

    @PostConstruct
    public void init() {
        this.visitorMap = Maps.newHashMap();
        visitorMap.put(OperationType.CREATE, new CreateVistor());
        visitorMap.put(OperationType.CLOSED, new CloseVistor());
        visitorMap.put(OperationType.EDIT_COMMENTS, new EditCommentVistor());
        visitorMap.put(OperationType.OTHERS, new OthersVistor());
        visitorMap.put(OperationType.REOPEN, new ReopenVistor());
        visitorMap.put(OperationType.TRANSFER, new TransferVistor());
        visitorMap.put(OperationType.URGE_ORDER, new UrgeVistor());
        visitorMap.put(OperationType.CLOSED_ORDERS, new BatchCloseVistor());
        visitorMap.put(OperationType.PENDING_ORDERS, new BatchPendVistor());
        visitorMap.put(OperationType.TRANSFER_ORDERS, new BatchTranferVistor());
    }

    /**
     * @ClassName logPointCut
     * @Description:切点信息
     **/
    @Pointcut("@annotation(com.jdl.omega.ticket.interceptor.OperationHis)")
    public void logPointCut() {

    }

    /**
     * @ClassName aroundForLog
     * @Description:执行完通知
     **/
    @AfterReturning(returning = "resp" , pointcut = "logPointCut()")
    public void aroundForLog(JoinPoint point, Object resp) {
        saveLogInfo(point, resp);
    }

    /**
     * @ClassName saveLogInfo
     * @Description: 保存操作日志
     **/
    public void saveLogInfo(JoinPoint joinPoint, Object resp) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        OperationHis operHis = method.getAnnotation(OperationHis.class);
        if (operHis == null) {
            return;
        }

        OperationType oprationType = operHis.oprationType();
        Object[] args = joinPoint.getArgs();
        try {
            LoginContext context = LoginContext.getLoginContext();
            String user = context.getPin();
            String nickName = context.getNick();

            // code !=0 代表业务逻辑执行异常。
            int code = JsonUtils.toJson(resp).get("code").getAsInt();
            if(code != 0 ){
                return;
            }

            List<History> histories = getHis(user, nickName,oprationType, args , resp);
            historyMapper.batchInsert(histories);
        } catch (Exception e) {
            logger.error("生成记录数据异常: ", e);
        }
    }

    private List<History> getHis(String user, String nickName, OperationType oprationType, Object[] args, Object resp){
        BaseVisitor visitor = visitorMap.get(oprationType);
        return visitor.visit(user, nickName, oprationType, args, resp);
    }
    public void insertHis(String user, String nickName,OperationType oprationType, Object[] args,Object resp){
        List<History> histories = getHis(user,nickName,oprationType,args,resp);
        historyMapper.batchInsert(histories);
    }

    public static void main(String[] args) {
        EnumUtils.isValidEnum(OperationType.class, "1");
        System.out.println(EnumUtils.isValidEnum(OperationType.class, "1"));
    }
}
posted @ 2023-11-13 17:40  SpecialSpeculator  阅读(5)  评论(0编辑  收藏  举报