为了基于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模式持强硬立场,或者至少对将其优势与复杂性相权衡表示怀疑。 他们的担忧是合理的。

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

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

  1. plsql 中的记录型变量和引用型变量

    /* plsql 中的记录型变量和引用型变量 查询某个员工的姓名和工资 练习记录型变量: 定义变量: emp_rec emp%rowtype; sql语句: select * into emp_rec ...

  2. JAVA中用什么来定义布尔型变量_Java 布尔型

    Java 布尔型 接下来,我们准备为大家介绍"布尔型". "布尔型"--布尔型只有真或假,它是关系表达式的运算结果,真是true,而假是false,而这种类型主 ...

  3. java异常对象引用变量_Java面向对象编程-异常处理

    第九章 异常处理 异常情况会改变正常的流程,导致恶劣的后果,为了减少损失,应该事先充分预料所有可能出现的异常,然后采取以下措施: 首先考虑避免异常,彻底杜绝异常的发生:如果不能完全避免,则尽可能地减少 ...

  4. java整型缓存_java整型缓存

    缓存大家应该都听说过,像计算机中的缓存用于提高计算机性能,浏览器的缓存会在下一次访问该网站时一定程度上提高访问速度.通常缓存是用空间换时间,那么java中既节省了内存又提高了效率的缓存大家是否知道呢? ...

  5. 怎样配置java的环境变量_java配置环境变量步骤

    在完成了JDK的安装后,环境变量设置是其安装后的首要操作,有人会问为什么要设置这个,要理解这个你首先要明白环境变量的涵义,它可以简单的理解为路径导向. . JAVA_HOMEC:\Usr\Java\j ...

  6. java 父类引用子类对象_java多态,如何理解父类引用指向子类对象

    java多态,如何理解父类引用指向子类对象 要理解多态性,首先要知道什么是"向上转型". 我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类.我可以通过   C ...

  7. java语言环境变量_JAVA语言环境变量的设置教程

    本文主要向大家介绍了JAVA语言环境变量的设置教程,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 安装JDK到目录,我这里是C:\Java 右键点击计算机属性 在系统变量里面建 JA ...

  8. java的环境变量_java学习册|JDK|环境变量

    每一个学java的小伙伴遇到的第一个拦路虎就是配置环境变量,而且关于环境变量,已经写过了不少文章,今天,我们不炒冷饭,我们来深入探讨下 往期文章 首先还是把什么是环境变量,如何配置环境变量讲一下,参考 ...

  9. java 取系统环境变量_java获取和设置系统变量(环境变量)

    一.Java获取环境变量 Java 获取环境变量的方式很简单: System.getEnv()  得到所有的环境变量 System.getEnv(key) 得到某个环境变量 Map map = Sys ...

最新文章

  1. 13SpringMvc_限定某个业务控制方法,只允许GET或POST请求方式访问
  2. Fiddler之Autoresponder替换(Web)
  3. 【湖南】2021年下半年软考报考时间及通知
  4. rxjava背压_如何形象地描述RxJava中的背压和流控机制?
  5. 搬了十次家,总算搬进了自己的家
  6. Visual Studio 2010 重构XAML的一个bug
  7. jqurey操作radio总结
  8. 告诉你一个可怕的数学事实:公路越多,城市越堵!
  9. Http Post 二进制通信
  10. python 怎么样去txt中提取xml_如何使用python将.txt文件转换成xml文件?
  11. vue 第六天(条件判断)
  12. Atititv2需求文档模板大纲目录 attilax总结
  13. mysql 分库分表 ~ ShardingSphere生态圈
  14. pcie16x能插1x的卡嘛?_存储先锋,雷克沙633x TF卡评测
  15. Java开发实习生面试—附简历以及面试题
  16. httpclient 下载文件
  17. 教你如何修改树莓派的时区和网络对时
  18. t检验、t分布、t值
  19. 致远V8.1 协同 最新版
  20. 个人修改机智云apk之出现couldn‘t find “libSDKLog.so“错误导致机智云apk在真机上调试出现keeps stopping错误解决方法

热门文章

  1. python网页信息_利用python处理网页信息
  2. paramiko模块_玩转网络自动化之Netmiko模块
  3. dev gridcontrol 单元格内容复制_Excel中的复制粘贴,不只是你想的那么简单的
  4. 想为自己设置的软件加一个属于自己的图标吗?使用AWT_Swing_图标解决你的问题(源码解析)
  5. java字面量和符号引用_JVM中的直接引用和符号引用
  6. 平衡二叉树——Balance Binary Sort Tree 设计与实现
  7. 如何在定制化组件中实现并使用v-model
  8. computed、watch和methods特性比较
  9. js原生方式实现bind方法
  10. ArrayList 类方法toArray的一点疑惑