• 浅谈设计模式的学习(中)


    在《浅谈设计模式的学习(上)》中我说到了设计模式的基石-----抽象思维。为什么需要抽象思维呢?因为越抽象就越不容易出错,就像有些领导人说话:坚持改革开放。但怎么算坚持改革开放呢,没有具体的标准,因事而异,所以就不容易违背这个坚持改革开放的原则了。

    3、学习设计模式,要保持抽象的思维

        什么是抽象思维呢?真的不好说,抽象的东西往往难以说明白,听了也难以搞明白,还是通过具体的例子来说吧

        有这么一个学生请假的场景,如果请假时间一天以内则有班长批准就可以了,三天以内则需要老师批准,超过三天就得找校长审批了,校长能审批不超过五天,超过五天就需要开会解决了。在这里我们就以这个场景为例,展示一下如何抽象编程。

      第一步:

           在上边的请假流程中我们看到了班长、老师、校长等实体(为了把注意力放在请假流程上,暂不对学生和请假实体多处理)。运用抽象思维我们抽象一下,这几个实体有什么共同特征呢?对他们都是人,好吧我们就写一个人的接口,但是里边该有什么方法呢?与我们上边需求相关的方法目前还没有,没关系,暂时空着

    public interface IPerson {
    
    }
    

     第二步:在第一步中绝对够抽象了吧,我们现在再具体一点吧,一步步往下具体。班长、老师、校长都是什么人呢?是不是都有一定的管理权力啊,而且在我们这个需求里,他们都有批准假期的权力,同时班长、校长都有自己的上级领导。现在我们的接口出来了:

    public interface IManager extends IPerson{
    	
    	public void process(Request request);
    	
    	public void setLeader(IManager leader);
    }
    

    这里用到了请求实体类:

    public class Request {
    
    	/**请假人名字*/
    	private String name;
    	/**请假天数*/
    	private int days;
    	/**请假原因*/
    	private String cause;
    	/**请假日期*/
    	private Date date;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getDays() {
    		return days;
    	}
    	public void setDays(int days) {
    		this.days = days;
    	}
    	public String getCause() {
    		return cause;
    	}
    	public void setCause(String cause) {
    		this.cause = cause;
    	}
    	public Date getDate() {
    		return date;
    	}
    	public void setDate(Date date) {
    		this.date = date;
    	}
    	
    }
    

    第三步:我们再往下具体,在IManager接口中有两个方法,设置领导的方法和处理请假请求的方法。试想一下,设置上级领导的方法对班长、老师和校长来说是不是都是一样的。同时处理请假的流程也是一样的,想想看,每个领导是不是都是先根据自己的批准能力来,如果请假天数在自己的批准能力范围内则处理,超过了则请求自己的上级领导批准。而具体怎么处理,每个领导则是不同的对吧。所以这里在一个抽象类里实现了设置领导和批假的模板方法,并抽象了一个具体批准处理的抽象方法。来看代码:

    public abstract class AbstractManager implements IManager{
    
    	protected IManager leader;
    	
    	protected int handleDay;
    	
    	/**
    	 * 
    	 * @param handleDay 能批准的天数
    	 */
    	public AbstractManager(int handleDay){
    		this.handleDay = handleDay;
    	}
    	
    	@Override
    	public void setLeader(IManager leader) {
    		this.leader=leader;
    	}
    	
    	@Override
    	public final void process(Request request) {
    		boolean isOk = handleRequest(request);
    		if(!isOk){
    			if(leader!=null){
    				leader.process(request);
    			}
    		}
    	}
    	/**假期处理方法*/
    	protected abstract boolean handleRequest(Request request);
    }
    

    第四步:好了到这里再往下具体就是我们的实体:班长、老师、校长了。他们有各自的假期处理方式。下边是班长、老师、校长三个实体类:

    班长类:

    public class Monitor extends AbstractManager {
    
    	public Monitor(int handleDay) {
    		super(handleDay);
    	}
    
    	@Override
    	public boolean handleRequest(Request request) {
    		if(this.handleDay>=request.getDays()){
    			System.out.println("班长:假期请求批准了");
    			return true;
    		}else{
    			System.out.println("班长:没有权限,请老师批准");
    			return false;
    		}
    	}
    }
    

    老师类:

    public class Teacher extends AbstractManager {
    
    	public Teacher(int handleDay) {
    		super(handleDay);
    	}
    
    	@Override
    	protected boolean handleRequest(Request request) {
    		if(this.handleDay>=request.getDays()){
    			System.out.println("老师:假期请求批准了");
    			return true;
    		}else{
    			System.out.println("老师:没有权限,让校长批准");
    			return false;
    		}
    	}
    }
    

    校长类:

    public class SchoolMaster extends AbstractManager {
    
    	public SchoolMaster(int handleDay) {
    		super(handleDay);
    	}
    
    	@Override
    	protected boolean handleRequest(Request request) {
    		if(this.handleDay>=request.getDays()){
    			System.out.println("校长:假期请求批准了");
    			return true;
    		}else{
    			System.out.println("校长:没有权限,我们开会商量一下");
    			return false;
    		}
    	}
    }
    

    第五步:我们以Client为学生做假期的请求申请,看看Client的代码:

    public class Client {
    	
    	public static void main(String[] args) {
    
    		Request request = new Request();
    		request.setName("小李");
    		request.setDays(6);
    		request.setDate(new Date());
    		request.setCause("不舒服");
    		
    		IManager monitor = new Monitor(1);
    		IManager teacher = new Teacher(3);
    		IManager master = new SchoolMaster(5);
    		
    		monitor.setLeader(teacher);
    		teacher.setLeader(master);
    		
    		monitor.process(request);
    	}
    
    }
    

    到这里整个流程结束了。这就是我们从抽象一步步走向具体的过程。聪明的你可能已经看出代码使用的什么设计模式。就是责任链模式。但这里有你更应该注意的一个设计模式-------模板方法模式。

       在AbstractManager的process方法中我们用了final修饰,就是不让子类重写此方法,因为客户端就是调用此方法来完成处理流程的,这是一个模板方法,在模板方法里我们调用了抽象方法handleRequest()。而handleRequest则是根据具体的领导具体实现。

       模板方法可以说是无处不在,比如servlet的service方法,如果你读一些开源项目,会发现更多的模板方法,所以掌握此模式绝对是有必要的。而模板方法模式就是将相同的处理流程提取到了抽象类中,具体处理方式则由子类来实现。所以一切还要从抽象开始。

      

  • 相关阅读:
    hg下拉和上传代码
    PC下ubuntu查找PC串口并加入用户组
    pyserial安装
    profile, bashrc, source, setup.*sh
    另一篇xtion、kinect选择比较(openni下)
    OpenCV、PCL;Xtion、kinect;OpenNI、kinect for windows SDK比较
    ROS安装环境配置及多版本的切换
    ubuntu安装软件或upgrade出现 You might want to run 'apt-get -f install' to correct these
    树莓派静态IP配置
    android之MP3播放器(1)
  • 原文地址:https://www.cnblogs.com/metoy/p/3719993.html
Copyright © 2020-2023  润新知