链式编程
假如当前有个A类,两个属性name和info(泛型),我们想用链式编程的方式给属性赋值,很简单,只要赋值的方法返回this即可
public class A<T> {
private String name;
private T info;
public A name(String name) {
this.name = name;
return this;
}
public A info(T info) {
this.info = info;
return this;
}
}
这样就可以用链式的方式构造A对象
A<String> a = new A<String>().name("pq").info("handsome");
抽象类
假如我们现在有多种A,都有name和info属性,此时我们可能会抽象出一个AbstractA,并把name和info属性移到抽象类中
public abstract class AbstractA<T> {
protected String name;
protected T info;
public AbstractA<T> name(String name) {
this.name = name;
return this;
}
public AbstractA<T> info(T info) {
this.info = info;
return this;
}
public abstract void doSomething();
}
然后用某个A1去继承这个抽象的A
public class A1<T> extends AbstractA<T>{
@Override
public void doSomething() {}
}
这时候问题出现了,原链式构造方式报错了

因为name(String name)返回的是AbstractA而不是它的实现A1,如果A1还有特殊属性也想用链式方式赋值那是链不到一起去的,显然不是想要的效果
解决
一个简单的思路是把name和info的赋值方法写到实现类中,但这样显然不好,明明是父类的属性却要每个子类都写一遍赋值方法,代码十分冗余
还有一种方式就是强转,也能达到效果,但写法太难看:
A1<String> a = (A1) (((A1) = new A1<String().name("pq")).info("handsome"));
回头看看问题本身,出现这个问题的主要原因在于抽象类AbstractA不知道子类是什么类型的,所以解决方案也出来了,可以在子类继承时把子类的类型通过泛型告知抽象类
修改抽象类如下
public abstract class AbstractA<S extends AbstractA<S, T>, T> {
protected String name;
protected T info;
public S name(String name) {
this.name = name;
return (S) this;
}
public S info(T info) {
this.info = info;
return (S) this;
}
public abstract void doSomething();
}
通过泛型S传入实现AbstractA的类的类型,赋值返回时强转为S,这时实现类只需要把自己的类型传入即可
public class A<T> extends AbstractA<A<T>, T> {
@Override
public void doSomething() {}
}
再次使用就及其丝滑了
A<String> a = new A<String>().name("pq").info("handsome");
总结
利用泛型,可以实现让父类得到子类的类型,这种方式很多场景其实都能用到,比如现在要定义一个可互相冲突的对象接口,就可以如下定义
public interface Conflictable<T extends Conflictable<T>> {
boolean conflictTo(T to);
}
网友评论