那些年,你不理解的回调知识

160 阅读4分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

1、回调的核心就是回调方将本身即this传递给调用方,这样调用方就可以在调用完毕之后告诉回调方它想要知道的信息。

同步调用:最直接简单的调用方式,类A的方法a()调用类B的方法b(),一直等待b()方法执行完毕,a()方法才能继续往下执行。这种调用方式适用于方法b()执行时间不长情况,因为b()方法执行时间一长或者直接阻塞的话,a()方法的余下代码是无法执行下去的,这样会造成整个流程的阻塞,带来的资源浪费问题和性能瓶颈。

2、异步调用:类似消息模式或事件监听,为了解决同步调用出现的阻塞导致整个流程卡住而产生的一种调用方式。类A的方法a()通过新起线程方式调用类B的方法b(),类A接着往下执行,无论方法b()执行时间多久不会阻塞方法a()的执行。这种方式在方法a()需要方法b()执行结果的情况下(视具体业务场景比如启动异步线程发个微信通知、刷新一个缓存这种没有必要),必须通过一定的措施对方法b()执行结果进行监听。在Java中,可以使用Future+Callable的方式完成。

3、回调:称之为“共轭调用”,我中调你,你中调我。形象的过程——类A的a()方法调用了类B的b()方法、类B的b方法执行完毕主动调用类A的callback()方法,一种双向的调用方式。经典的回调函数是一个函数或者过程,由调用方自己实现,供被调用方使用的特殊函数。面向对象中,回调常常通过抽象类或者接口来实现,实现该接口的类为回调类,回调类的对象为回调对象。

实践指南:

入门样例: 1、直接本类处理结果

public class Student
{
	private String name=null;
	public Student(String name)
	{
		this.name=name;
	}
	public void setName(String name)
	{
		this.name=name;
	}
	private int calcADD(int a,int b)
	{
		return a+b;
	}
	public void printBlank(int a,int b)
	{
		int result=calcADD(a,b);
		System.out.println(name+":"+a+"+"+b+"="+result);
	}
}
public class Test
{
	public static void main(String[] args)
	{
		int a=1;
		int b=2;
		Student s=new Student("明");
		s.printBlank(a,b);
	}
}

2、中级阶段:通过求助专门的职责类来完成功能转移,但是结果的输出还是需要本类来完成

public class Calculator
{
	public int add(int a,int b)
	{
		return a+b;
	}
}
public class Student
{
	private String name=null;
	public Student(String name)
	{
		this.name=name;
	}
	public void setName(String name)
	{
		this.name=name;
	}
	private int calcADD(int a,int b)
	{
		return a+b;
	}
	private int useCalculator(int a,int b)
	{
		return new Calculator().add(a,b);
	}
	public void printBlank(int a,int b)
	{
		int result=useCalculator(a,b);
		System.out.println(name+"委托计算器:"+a+"+"+b+"="+result);
	}
}
public class Test
{
	public static void main(String[] args)
	{
		int a=618;
		int b=111;
		Student s=new Student("明");
		s.printBlank(a,b);
	}
}

3、开始触及回调边缘:除了完成功能转移,结果的输出也委托给职责类来完成。(通过将自身引用暴露给职责类)

public class SuperCalculator
{
	public void add(int a,int b,Student student)
	{
		int result=a+b;
		student.printBlank(a,b,result);
	}
}
public class Student
{
	private String name=null;
	public Student(String name)
	{
		this.name=name;
	}
	public void setName(String name)
	{
		this.name=name;
	}
	public void callHelp(int a,int b)
	{
		new SuperCalculator().add(a,b,this);
	}
	public void printBlank(int a,int b,int result)
	{
		System.out.println(name+"委托计算机:"+a+"+"+b+"="+result);
	}
}
public class Test
{
	public static void main(String[] args)
	{
		int a=26579;
		int b=16417;
		Student s=new Student("明");
		s.callHelp(a,b);
	}
}

上面的例子中回调功能就正式登场了,其中的printBlank方法就是回调函数 4、推而广之,继续抽象 将具体的被委托类里的通用的业务方法抽取到接口中,然后由具体的实现类来定制完成;同时修改职责类的业务方法入参为接口,而不是具体的被委托类。(此处体现了面向抽象接口而不是具体实现类思想,也有开闭原则的 思想在里面)

public interface DoJob {
    void handleJob(int a,int b,int res);
}
public class SuperCalulator
{
	public void add(int a,int b doJob customer)
	{
		int result=a+b;
		customer.printBlank(a,b,result);
	}
}
public class Student
{
	private String name=null;
	public Student(String name)
	{
		this.name=name;
	}
	public class doHomeWork implements doJob
	{
		@Override
		public void printBlank(int a,int b,int result)
		{
			System.out.println(name+"委托计算:"+a+"+"+b+"="+result);
		}
	}
	public void callHelp(int a,int b)
	{
		new SuperCalculator().add(a,b,new doHomeWork());
	}
}
public class Boss
{
	private String name=null;
	public Boss(String name)
	{
		this.name=name;
	}
	public setName(String name)
	{
		this.name=name;
	}
	public class doHomeWork implements doJob
	{
		@Override
		public void printBlank(int a,int b,int result)
		{
			System.out.println(name+"委托算账:"+a+"+"+b+"="+result+"元";)
		}
	}
	public void callHelp(int a,int b)
	{
		new SuperCalculator().add(a,b,new doHomeWork());
	}
}

测试:

public class Test
{
	public static void main(String[] args)
	{
		int a=66;
		int b=88;
		int c=22337;
		int d=11226;
		Student s1=new Student("明兄弟");
		Boss s2=new Boss("老板");
		
		s1.callHelp(a,b);
		s2.callHelp(c,d);
	}
}