java引用型变量_java-有没有办法用类型变量引用当前类型?

为了基于StriplingWarrior的答案,我认为以下模式将是必要的(这是分层流利的Builder API的配方)。

首先,一个基本抽象类(或接口)列出了返回扩展该类实例的运行时类型的协定:

/**

* @param The runtime type of the implementor.

*/

abstract class SelfTyped> {

/**

* @return This instance.

*/

abstract SELF self();

}

所有中间扩展类都必须是QueryBuilder并维护递归类型参数Where:

public abstract class MyBaseClass>

extends SelfTyped {

MyBaseClass() { }

public SELF baseMethod() {

//logic

return self();

}

}

可以以相同的方式遵循其他派生类。 但是,这些类都不能直接用作变量类型,而无需诉诸原始类型或通配符(这违背了模式的目的)。 例如(如果QueryBuilder不是Where):

//wrong: raw type warning

MyBaseClass mbc = new MyBaseClass().baseMethod();

//wrong: type argument is not within the bounds of SELF

MyBaseClass mbc2 = new MyBaseClass().baseMethod();

//wrong: no way to correctly declare the type, as its parameter is recursive!

MyBaseClass> mbc3 =

new MyBaseClass>().baseMethod();

这就是我将这些类称为“中间类”的原因,因此也都应将它们都标记为QueryBuilder。为了闭合循环并利用模式,必须使用“叶子”类,这些类可以解析继承的类型参数 Where具有自己的类型和实现Having。还应标记Or,以避免违反合同:

public final class MyLeafClass extends MyBaseClass {

@Override

MyLeafClass self() {

return this;

}

public MyLeafClass leafMethod() {

//logic

return self(); //could also just return this

}

}

这些类使模式可用:

MyLeafClass mlc = new MyLeafClass().baseMethod().leafMethod();

AnotherLeafClass alc = new AnotherLeafClass().baseMethod().anotherLeafMethod();

这里的价值是方法调用可以在类层次结构中上下链接,同时保持相同的特定返回类型。

免责声明

上面是Java中奇怪重复模板模式的实现。 这种模式并非天生就安全,应仅保留其内部API的内部功能。 原因是不能保证上述示例中的类型参数QueryBuilder实际上将解析为正确的运行时类型。 例如:

public final class EvilLeafClass extends MyBaseClass {

@Override

AnotherLeafClass self() {

return getSomeOtherInstanceFromWhoKnowsWhere();

}

}

本示例在模式中暴露了两个孔:

QueryBuilder可以“撒谎”并用任何其他扩展Where的类型替换为Having。

除此之外,我们无法保证3002891441841631636352实际上会返回Where,这可能是问题,也可能不是问题,具体取决于基本逻辑中状态的使用。

由于这些原因,这种模式很可能被滥用或滥用。 为防止这种情况,不允许公开涉及的任何类-请注意我在QueryBuilder中使用package-private构造函数,该构造函数替换了隐式的public构造函数:

MyBaseClass() { }

如果可能的话,也将QueryBuilder的包私有设置为私有,这样就不会给公共API带来噪音和混乱。 不幸的是,这仅在Where是抽象类的情况下才有可能,因为接口方法是隐式公共的。

正如zhong.j.yu在评论中指出的那样,可以简单地删除QueryBuilder上的边界,因为它最终无法确保“自我类型”:

abstract class SelfTyped {

abstract SELF self();

}

Yu建议仅依赖合同,避免因直觉上的递归范围而引起的任何混乱或错误的安全感。 就个人而言,由于QueryBuilder表示Java中self类型的最可能表达,因此我更倾向于保留界限。 但是,于的观点肯定与QueryBuilder所设定的先例相吻合。

结论

这是一个值得的模式,它允许对构建器API进行流畅且富有表现力的调用。 我在认真的工作中使用了几次,最著名的是编写了一个自定义查询构建器框架,该框架允许如下调用站点:

List foos = QueryBuilder.make(context, Foo.class)

.where()

.equals(DBPaths.from_Foo().to_FooParent().endAt_FooParentId(), parentId)

.or()

.lessThanOrEqual(DBPaths.from_Foo().endAt_StartDate(), now)

.isNull(DBPaths.from_Foo().endAt_PublishedDate())

.or()

.greaterThan(DBPaths.from_Foo().endAt_EndDate(), now)

.endOr()

.or()

.isNull(DBPaths.from_Foo().endAt_EndDate())

.endOr()

.endOr()

.or()

.lessThanOrEqual(DBPaths.from_Foo().endAt_EndDate(), now)

.isNull(DBPaths.from_Foo().endAt_ExpiredDate())

.endOr()

.endWhere()

.havingEvery()

.equals(DBPaths.from_Foo().to_FooChild().endAt_FooChildId(), childId)

.endHaving()

.orderBy(DBPaths.from_Foo().endAt_ExpiredDate(), true)

.limit(50)

.offset(5)

.getResults();

关键是QueryBuilder不仅是一个简单的实现,而是从复杂的构建器类层次结构扩展而来的“叶子”。 相同的模式用于辅助程序,例如Where、Having、Or等,所有这些都需要共享大量代码。

但是,您不应忘记所有这些最终仅构成语法糖这一事实。 一些经验丰富的程序员对CRT模式持强硬立场,或者至少对将其优势与复杂性相权衡表示怀疑。 他们的担忧是合理的。

最重要的是,在实现它之前仔细研究一下它是否真的必要-如果这样做,则不要使其可公开扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值