记录最近在项目设计中遇到的一个小问题。

前提:有这样两个POJO类,它们都可以通过链式调用的方式来设置其属性值,其中一个类继承了另一个类。

问题:通过链式调用,子类对象访问父类方法后,如何使返回对象仍是子类对象,仍然可以继续链式调用子类的方法?

结论:子类重写父类中需要被调用的方法。在子类重写的方法中,首先通过super关键字调用父类方法,

然后通过return this语句返回子类对象。

为了更具体、更形象的描述问题和解决办法,上示例代码。

BaseOption、AppearanceOption 是两个实现了链式调用的POJO类,其中AppearanceOption 继承自BaseOption。

 package com.practice.option;

 public class BaseOption {

     private String id;

     private String name;

     public String getId() {
return id;
} public String getName() {
return name;
} public BaseOption setId(String id) {
this.id = id;
return this;
} public BaseOption setName(String name) {
this.name = name;
return this;
} }
 package com.practice.option;

 public class AppearanceOption extends BaseOption {

     private String color;

     private String shape;

     private String size;

     public String getColor() {
return color;
} public String getShape() {
return shape;
} public String getSize() {
return size;
} public AppearanceOption setColor(String color) {
this.color = color;
return this;
} public AppearanceOption setShape(String shape) {
this.shape = shape;
return this;
} public AppearanceOption setSize(String size) {
this.size = size;
return this;
} }

此时,AppearanceOption 类的对象调用父类的方法后,返回的是父类对象。

如下图,setId()方法返回的是BaseOption对象,eclipse自动提示中看不到子类的方法。

修改子类AppearanceOption 的代码,重写父类方法。

 package com.practice.option;

 public class AppearanceOption extends BaseOption {

     private String color;

     private String shape;

     private String size;

     public String getColor() {
return color;
} public String getShape() {
return shape;
} public String getSize() {
return size;
} public AppearanceOption setColor(String color) {
this.color = color;
return this;
} public AppearanceOption setShape(String shape) {
this.shape = shape;
return this;
} public AppearanceOption setSize(String size) {
this.size = size;
return this;
} @Override
public AppearanceOption setId(String id) {
super.setId(id);
return this;
} @Override
public AppearanceOption setName(String name) {
super.setName(name);
return this;
} }

现在setId()方法返回的是AppearanceOption 对象,eclipse自动提示中可以看到子类的方法了。

从结论来看,并没有用到多么高深的技术,主要还是对面向对象特征的理解和运用。可是,在实际设计代码结构的时候愣是半天没想到。

主要的解决思路是来自Java源码的启发。在Java中,最常见的链式调用就是 StringBuffer、StringBuilder 类中的 append() 方法。我们可以通过连续的.append().append()方法来完成字符串的拼接。如果稍微熟悉源码,可能会知道 StringBuffer、StringBuilder 这两个类都继承自抽象类AbstractStringBuilder,该抽象类中也有append() 方法。答案显而易见了,查看一下 StringBuffer 或者 StringBuilder 的源码就知道了。


扩展问题:

1.什么情况下适合采用这种链式的方法调用?

这里使用的所谓链式调用,实际上是同一个对象的多个方法的连续调用。也就是说,在这个长链中的每个方法返回的都是相同的类型,相同的对象。例如,StringBuilder中append方法的连续调用,JSONObject中的accumulate、put等方法也可以连续调用。这些被调用的方法都有“构建”的特性,都是用于完善实例对象。使用链式调用代码容易编写,看起来比较简洁也容易阅读和理解,但也应该注意代码长度,适当换行。

如果被调用的方法返回的类型不同,则不适合链式调用。因为各方法返回的类型被隐藏了,代码不容易理解,另外在Debug的时候也是比较麻烦的。

2.对于项目来说,采用这种继承结构是否合理?是否设计过度?

对于简单的POJO类来说,如果类中的属性个数在十几个以内,我觉得完全没必要用继承。

如果各POJO类中属性个数较多,重复的属性也较多的情况,可以考虑使用继承。

另外就是一些属性的设置过程需要对外隐藏,或者需要对外使用统一的对象类型,这时可以考虑使用继承。

就本次项目而言,类的属性值并没有那么多,个人认为不需要搞那么复杂。但是领导说“对外要使用统一的对象类型”,上层设计又不让我插手。

所以,那就这样吧~~~~~~

【Java】子类的链式调用的更多相关文章

  1. javascript学习(10)——[知识储备]链式调用

    上次我们简单的说了下单例的用法,这个也是在我们java中比较常见的设计模式. 今天简单说下链式调用,可能有很多人并没有听过链式调用,但是其实只要我简单的说下的话,你肯定基本上都在用,大家熟知的jQue ...

  2. 基于JDK动态代理实现的接口链式调用(Fluent Interface)工具

    什么是链式接口(Fluent Interface) 根据wikipedia上的定义,Fluent interface是一种通过链式调用方法来完成方法的调用,其操作分为终结与中间操作两种.[1] 下面是 ...

  3. 疯狂的类构造器Builder模式,链式调用

    疯狂的类构造器 最近栈长在做 Code Review 时,发现一段创建对象的方法: Task task = new Task(112, "紧急任务", "处理一下这个任务 ...

  4. 如何写 JS 的链式调用 ---》JS 设计模式《----方法的链式调用

    1.以$ 函数为例.通常返回一个HTML元素或一个元素集合. 代码如下: function $(){ var elements = []; ;i<arguments.length;i++){ v ...

  5. hasOwnProperty 递归 简单回调 链式调用

    1.hasOwnProperty 函数的返回值为Boolean类型.如果对象object具有名称为propertyName的属性,则返回true,否则返回false. function Box(){ ...

  6. swift学习笔记之-可选链式调用

    //可选链式调用 import UIKit /*可选链式调用(Optional Chaining) 1.在可选值上请求和调用该可选值的属性.方法及下标的方法,如果可选值有值,那么调用就会成功,返回可选 ...

  7. Swift2.1 语法指南——可空链式调用

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

  8. JavaScript设计模式——方法的链式调用

    方法的链式调用: (function() { //私有类 function _$ (els) { this.elements = []; for(var i = 0, len = els.length ...

  9. jQuery的XX如何实现?——2.show与链式调用

    往期回顾: jQuery的XX如何实现?——1.框架 -------------------------- 源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看 ...

随机推荐

  1. Ajax的二次封装

    function handleAjax(url,_data,method) { return ajax(url,_data,method).then(function (res) { if(res){ ...

  2. MVC Castle依赖注入实现代码

    1.MVc 实现依赖注入 public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKe ...

  3. OC整理1

    关于面向对象 看起来简单,好好体会其实有点深奥,初学的时候更感觉抽象,可能由于开发经验不足的关系吧,很难体会到面向对象的精髓. 放轻松,我们来用最直白得方式来探讨一下面向对象. 首先,编程是为了用计算 ...

  4. myeclipse中导入js报如下错误Syntax error on token "Invalid Regular Expression Options", no accurate correc

    今天在使用bootstrap的时候引入的js文件出现错误Syntax error on token "Invalid Regular Expression Options", no ...

  5. SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/D:/MyEclipseWorkSpace/Emps/WebRoot/WEB-INF/lib/slf4j-nop-1.5.6.

    错误的是HQL语句,注意写类名属性名无误,条件无误.

  6. 初试Office 365企业版E3

    Microsoft Office 365 团队给了所有现任的MVP 12个月的微软 Office 365 企业 E3 订阅,今天激活账号并试用了一下,发现非常强大,本文简要介绍下Office 365 ...

  7. 一步步学习javascript基础篇(1):基本概念

    一.数据类型 数据类型 基本数据类型(五种) Undefined Null Boolean Number String 复杂数据类型(一种) Object Undefined:只有一个值undefin ...

  8. Java NIO1:I/O模型概述

    I/O模型 在开始NIO的学习之前,先对I/O的模型有一个理解,这对NIO的学习是绝对有好处的.我画一张图,简单表示一下数据从外部磁盘向运行中进程的内存区域移动的过程: 这张图片明显忽略了很多细节,只 ...

  9. 剑指Offer面试题:5.重建二叉树

    一.题目:重建二叉树 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序 ...

  10. 【大型网站技术实践】初级篇:搭建MySQL主从复制经典架构

    一.业务发展驱动数据发展 随着网站业务的不断发展,用户量的不断增加,数据量成倍地增长,数据库的访问量也呈线性地增长.特别是在用户访问高峰期间,并发访问量突然增大,数据库的负载压力也会增大,如果架构方案 ...