接上篇:https://developer.aliyun.com/article/1228148?spm=a2c6h.13148508.setting.27.21084f0eNCKPti
六、 定义Holder类实现参数的输出
在很多语言中,函数的参数都有输入(in)、输出(out)和输入输出(inout)之分。在C/C++语言中,可以用对象的引用(&)来实现函数参数的输出(out)和输入输出(inout)。
但在Java语言中,虽然没有提供对象引用类似的功能,但是可以通过修改参数的字段值来实现函数参数的输出(out)和输入输出(inout)。
这里,我们叫这种输出参数对应的数据结构为Holder(支撑)类。
1. Holder类实现代码
2. Holder类使用案例
其实,可以实现一个泛型支撑类,适用于更多的数据类型。
七、 定义Union类实现数据体的共存
在C/C++语言中,联合体(union),又称共用体,类似结构体(struct)的一种数据结构。联合体(union)和结构体(struct)一样,可以包含很多种数据类型和变量,两者区别如下:
• 结构体(struct)中所有变量是“共存”的,同时所有变量都生效,各个变量占据不同的内存空间;
• 联合体(union)中是各变量是“互斥”的,同时只有一个变量生效,所有变量占据同一块内存空间。
当多个数据需要共享内存或者多个数据每次只取其一时,可以采用联合体(union)。
在Java语言中,没有联合体(union)和结构体(struct)概念,只有类(class)的概念。众所众知,结构体(struct)可以用类(class)来实现。其实,联合体(union)也可以用类(class)来实现。但是,这个类不具备“多个数据需要共享内存”的功能,只具备“多个数据每次只取其一”的功能。
这里,以微信协议的客户消息为例说明。根据我多年来的接口协议封装经验,主要有以下两种实现方式。
1. 使用函数方式实现Union
1) Union类实现
/** 客户消息类 */ @ToString public class CustomerMessage {
/** 属性相关 */ /** 消息类型 */ private String msgType; /** 目标用户 */ private String toUser;
/** 共用体相关 */ /** 新闻内容 */ private News news; ...
/** 常量相关 */ /** 新闻消息 */ public static final String MSG_TYPE_NEWS = "news"; ...
/** 构造函数 */ public CustomerMessage() {}
/** 构造函数 */ public CustomerMessage(String toUser) { this.toUser = toUser; }
/** 构造函数 */ public CustomerMessage(String toUser, News news) { this.toUser = toUser; this.msgType = MSG_TYPE_NEWS; this.news = news; }
/** 清除消息内容 */ private void removeMsgContent() { // 检查消息类型 if (Objects.isNull(msgType)) { return; }
// 清除消息内容 if (MSG_TYPE_NEWS.equals(msgType)) { news = null; } else if (...) { ... } msgType = null; }
/** 检查消息类型 */ private void checkMsgType(String msgType) { // 检查消息类型 if (Objects.isNull(msgType)) { throw new IllegalArgumentException("消息类型为空"); }
// 比较消息类型 if (!Objects.equals(msgType, this.msgType)) { throw new IllegalArgumentException("消息类型不匹配"); } }
/** 设置消息类型函数 */ public void setMsgType(String msgType) { // 清除消息内容 removeMsgContent();
// 检查消息类型 if (Objects.isNull(msgType)) { throw new IllegalArgumentException("消息类型为空"); }
// 赋值消息内容 this.msgType = msgType; if (MSG_TYPE_NEWS.equals(msgType)) { news = new News(); } else if (...) { ... } else { throw new IllegalArgumentException("消息类型不支持"); } }
/** 获取消息类型 */ public String getMsgType() { // 检查消息类型 if (Objects.isNull(msgType)) { throw new IllegalArgumentException("消息类型无效"); }
// 返回消息类型 return this.msgType; }
/** 设置新闻 */ public void setNews(News news) { // 清除消息内容 removeMsgContent();
// 赋值消息内容 this.msgType = MSG_TYPE_NEWS; this.news = news; }
/** 获取新闻 */ public News getNews() { // 检查消息类型 checkMsgType(MSG_TYPE_NEWS);
// 返回消息内容 return this.news; }
... } |
2) Union类使用
3) 主要优缺点
• 优点:更贴近C/C++语言的联合体(union);
• 缺点:实现逻辑较为复杂,参数类型验证较多。
2. 使用继承方式实现Union
1) Union类实现
/** 客户消息类 */ @Getter @Setter @ToString public abstract class CustomerMessage { /** 属性相关 */ /** 消息类型 */ private String msgType; /** 目标用户 */ private String toUser;
/** 常量相关 */ /** 新闻消息 */ public static final String MSG_TYPE_NEWS = "news"; ...
/** 构造函数 */ public CustomerMessage(String msgType) { this.msgType = msgType; }
/** 构造函数 */ public CustomerMessage(String msgType, String toUser) { this.msgType = msgType; this.toUser = toUser; } }
/** 新闻客户消息类 */ @Getter @Setter @ToString(callSuper = true) public class NewsCustomerMessage extends CustomerMessage {
/** 属性相关 */ /** 新闻内容 */ private News news;
/** 构造函数 */ public NewsCustomerMessage() { super(MSG_TYPE_NEWS); }
/** 构造函数 */ public NewsCustomerMessage(String toUser, News news) { super(MSG_TYPE_NEWS, toUser); this.news = news; } } |
2) Union类使用
3) 主要优缺点
• 优点:使用虚基类和子类进行拆分,各个子类对象的概念明确;
• 缺点:与C/C++语言的联合体(union)差别大,但是功能上大体一致。
在C/C++语言中,联合体并不包括联合体当前的数据类型。但在上面实现的Java联合体中,已经包含了联合体对应的数据类型。所以,从严格意义上说,Java联合体并不是真正的联合体,只是一个具备“多个数据每次只取其一”功能的类。
接下篇:https://developer.aliyun.com/article/1228146?groupCode=java