访问者模式
访问者模式
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"));
}
}
原创:做时间的朋友