在java中,是否可以创建一个流畅的可扩展类层次结构,其中包含可以按任何顺序调用的方法?

在java中,是否可以创建一个流畅的可扩展类层次结构,其中包含可以按任何顺序调用的方法?,java,design-patterns,generics,runtime-error,method-chaining,Java,Design Patterns,Generics,Runtime Error,Method Chaining,是否可以在java中创建一个可扩展的类层次结构,其方法是流畅的,并且可以以任何顺序调用(是的!请参见下面的答案),即使对于现有类,如果方法是fluant,当您无法访问源代码时也是如此 我正在改造一个现有的层次结构,并希望使用一个工厂或至少是一个通用的构造函数和(最终)不可变的构建器模式(JBP.14)。设置字段的方法返回void——最好是返回一个通用的T——这样我们就能够进行方法链接(现在它们都调用super) 目标: 1. 避免在每个类中创建静态getFactory()方法。 2. 简单方

是否可以在java中创建一个可扩展的类层次结构,其方法是流畅的,并且可以以任何顺序调用(是的!请参见下面的答案),即使对于现有类,如果方法是fluant,当您无法访问源代码时也是如此

我正在改造一个现有的层次结构,并希望使用一个工厂或至少是一个通用的构造函数和(最终)不可变的构建器模式(JBP.14)。设置字段的方法返回
void
——最好是返回一个通用的
T
——这样我们就能够进行方法链接(现在它们都调用
super

目标:
1. 避免在每个类中创建静态getFactory()方法。
2. 简单方法签名。
3. 创建一个通用的工厂方法,但在编译时会发现问题。
4. 出错时,获取编译时错误,而不是运行时错误。

按照要求,非泛型代码非常简单,但不起作用

public class A {
    private String a = null;
    protected A setA(String a){
        this.a = a;
        return this;//<== DESIRE THIS TO BE CHAINABLE
    }
    protected static A factory(){
       return new A();
    }
}  
公共A类{
私有字符串a=null;
受保护的setA(字符串A){
这个a=a;
回答这个;//答案(令我惊讶和满意)是肯定的。我自己回答了这个问题:
如果方法调用返回有问题的类的实例(请参见下面的chainable),您只需做一点工作就可以做到这一点。如果您可以编辑顶级源代码,我还发现了一种更简单的方法:

在顶级课程(A)中:

受保护的最终TA(T型){
返回类型
}
假设C延伸B,B延伸A

援引:

C=newc();
//任何命令都可以,并且您有编译时安全性和IDE帮助。
c、 setA(“a”).a(c).setB(“b”).a(c).setC(“c”);
示例1和3是使现有类层次结构流畅的方法,并允许在现有类流畅的情况下以任何顺序调用方法(但您无权访问或无法更改源)。WAY2是一个示例,您可以访问源,并希望调用尽可能简单

完整SSCCE:

导入静态java.lang.System.out;
公共类测试仪{
公共静态void main(字符串[]args){
//测试1:
for(intx:newint[]{0,1,2}){
A w=getA(x);
//我同意这是一种肮脏的方式…但你可以做到。
链.a(w.setA(“a1”)).a(w实例f C?((C)w).setC(“c1”):空);
out.println(w);
}
//测试方法2:希望这能得到保罗·贝洛拉的认可
//为了简洁、易用和语法上的方便。
C=新的C();
//以编译时类型安全的任何顺序调用方法!
c、 setA(“a2”).a(c).setB(“b2”).a(c).set(“C2”);
out.println(w);
//示例3,即示例1,但已知顶级类为“C”
//但是您没有访问源的权限,无法将“a”方法添加到
//方法调用不必像示例1那样令人讨厌。
c=新的c();
Chain.a(c.setA(“a3”)).a(c.setB(“b3”)).a(c.setC(“c3”);//不比示例2大多少。
out.println(w);
}
公共静态getA(inta){//工厂方法。
retval;//我不喜欢多次返回。
开关(a){
案例0:retval=newa();中断;
案例1:retval=new B();中断;
默认值:retval=newc();break;
}
返回返回;
}
}
甲级考试

公共A类{
私人字符串a;
受保护的字符串getA(){return a;}
//方式2-在这里您可以访问顶级源类。
受保护的最终T a(T type){return type;}//这太棒了!
受保护的集合A(字符串A){this.A=A;返回this;}//Fluent方法
@凌驾
公共字符串toString(){
返回“A[getA()=”+getA()+“]”;
}
}
B级考试

公共类B扩展了{
私有字符串b;
受保护的字符串getB(){return b;}
受保护的B setB(字符串B){this.B=B;返回this;}//Fluent方法
@凌驾
公共字符串toString(){
返回“B[getA()=”+getA()+”,getB()=“+getB()+”]\n
+super.toString();
}
}
测试等级C

公共类C扩展B{
私有字符串c;
受保护的字符串getC(){return c;}
受保护的C setC(字符串C){this.C=C;返回this;}//Fluent方法
@凌驾
公共字符串toString(){
返回“C[getA()=”+getA()+”,getB()=“+getB()+”,getC()=”
+getC()+“]\n”+super.toString();
}
}
链类

/**
*允许与任何类链接,即使是您没有编写和没有的类
*访问的源代码,只要该类是流畅的。
*@作者Gregory G.Bishopggb667@gmail.com(C)2013年11月5日保留所有权利。
*/
公共最终类链{
公共静态ua(K值){//注意这是静态的
返回新的uz(value);//这样IDE名称就不会令人讨厌了
}
}
Chain的助手类

/**
*实例方法无法从链重写静态方法,
*这就是此类存在的原因(即抑制IDE警告,
*并提供流畅的使用)。
*
*@作者Gregory G.Bishopggb667@gmail.com(C)2013年11月5日保留所有权利。
*/
期末班{
public T a;//因此我们可以从链中的最后一个链接获取返回值。
受保护的T(T){this.a=T}//上面的链需要
公共uA(K值){
返回新的u0(值);
}
}
输出:

A[get(A)=A]
B[get(A)=A,getB()=null]
A[getA()=A]
C[getA()=a,getB()=null,getC()=C]
B[get(A)=A,getB()=null]
A[得到(A)=A]
QED:)

我从未见过有人这样做,我认为这可能是一个新的和潜在的
public class B extends A {
    private String b = null;
    protected Foo setB(String b){
        this.b = b;
        return this;//<== DESIRE THIS TO BE CHAINABLE
    }
    protected static B factory(){
        return new B();
    }
}
Book b = null; Publisher p = null; List books = null; String id = "Elric of Melnibone"; books = Chain.a(b = findBook(id)).a(b != null ? p = b.getPublisher() : null) .a(p != null ? p.getPublishedBooks(): null).a; out.println(books==null ? null : Arrays.toString(books.toArray())); Book b = null; Publisher p = null; List books = null; String id = "Elric of Melnibone"; b = findBook(id); Array[] books = null; if( b != null ) { p = b.getPublisher(); if(p != null) { books = p.getPublishedBooks(); } } out.println(books==null ? null : Arrays.toString(books.toArray()));
    B<B> b = B.factoryB();
    b.setA("a").setB("b");

    A<A> ba = A.factoryA();

    ba.setA("a");
public  class A<S extends A> extends Chained<S> {
    private String a = null;

    protected A() {
        }

    public S setA(String a) {
        this.a = a;
        return me();
    }
    public static A<A> factoryA() {
        return new A<A>();
    }
}
public  class B<S extends B> extends A<S> {
    private String b = null;

    B() {
    }

    public S setB(String b) {
        this.b = b;
        return me();
    }
    public static B<B> factoryB() {
        return new B<B>();

    }

}
public  abstract class Chained<S extends Chained> {
    // class should be extended like:
    // ... class A<S extends A> extends Chained<S>

    public Chained() {
    }

    public final S me() {
        return (S) this;
    }
}
BaseA
 +- A
 +- BaseB
     +- B


public class BaseA<S extends BaseA<?>> {
    private String a = null;

    protected BaseA() {
    }

    @SuppressWarnings("unchecked")
    public S setA(String a) {
        this.a = a;
        return (S) this;
    }

}

public class A extends BaseA<A> {
    public static A factoryA() {
        return new A();
    }
}

public class BaseB<S extends BaseB<?>> extends BaseA<S> {
    private String b = null;

    protected BaseB() {
    }

    @SuppressWarnings("unchecked")
    public S setB(String b) {
        this.b = b;
        return (S) this;
    }

}

public class B extends BaseB<B> {
    public static B factoryB() {
        return new B();
    }
}

public class Main {
    public static void main(String[] args) {
        B.factoryB().setA("").setB("").setB("").setA("").setA("");
    }
}