※ 引述《JGC18 (JGC)》之铭言:
: 各位先进好:
: 小弟今天有一台设备,假设回应资料的长度会有,250bytes, 120bytes, 60bytes
: 这250bytes,假设依照规格总共可以解析出10个字段(字段编号为A,B,C,D,E,F,G,H,I,J)
: 120bytes,可以解析出6个字段(字段编号为 A,D,E,F,I,J)
: 60bytes,可以解析出3个字段 (字段编号为 B,C,D)
: 250个bytes等于是完整的所有资料回复
: 如果有错误,就是回应120bytes跟60bytes
: 我目前想到的方法是用一个class类似这样
在进行设计之前,
可以先思考一下当前需求以及未来有无扩充或改变需求的可能。
依照你的叙述,
每一次回应的资料可能有3种不同的长度,
又分别对应到不同数量和种类的字段。
首先可以想到的问题是:
未来有没有可能会多一种回应的长度?比如180bytes?
字段顺序改变 => A,B,C,D -> B,D,A,C
字段种类改变 => A,B,C,D -> A,B,C,E
字段型态改变 => int A -> String A
有了一些概念之后才比较可能设计出比较弹性的程式,
未来面对需求改变的时候也比较容易改动。
假设今天这台设备回传的三种不同长度资料分别为,
月收入(250 bytes),固定收入(120 bytes),投资损益(60 bytes)。
从结果来看,
你可能会想要类似这样子的类别。
public class Income{
private String name;
private int income;
private int salary;
private int foodAllowances;
private boolean absence;
//以下略
public String getName(){
return this.name;
}
//以下略
}
public class Salary{
private int salary;
private int foodAllowances;
private boolean absence;
//以下略
}
public class Investment{
//略
}
这三种类别必须要先确定且定义好提供外界存取的方法,
再来思考如何将各个值塞进去。
另外为了保留字段顺序的弹性,
我们希望这个顺序可以定义在程式以外的地方。
在执行期间读入外部的顺序,
再利用reflection的方式依序将各字段塞入对应的属性内。
因此我们需要一个父类别帮我们赋予各个属性的值。
public abstract class BaseBean {
//字段及长度
protected abstract LinkedHashMap<String, Integer> getFields();
//index of byte array
private int index = 0;
public void parse(byte[] input){
try{
for(Entry<String, Integer> entry : this.getFields().entrySet()){
Field field = this.getClass().getField(entry.getKey());
Class<?> clazz = field.getType();
int length = entry.getValue();
Object value = translate(input, clazz, length);
field.set(this, value);
}
}catch (Exception e){
//略
}
}
protected Object translate(byte[] input, Class<?> clazz, int length){
Object result = null;
if(clazz.equals(int.class)){
result = translateToInt(input);
}else if(clazz.equals(String.class)){
result = translateToString(input, length);
}else{
//略
}
return result;
}
//byte to int
private int translateToInt(byte[] input){
final int LENGTH = 4;
byte[] cell = Arrays.copyOfRange(input, index, LENGTH);
index += LENGTH;
int result = 0;
//略
return result;
}
//byte to String
private String translateToString(byte[] input, int length){
final int BYTE_LENGTH = 2;
final String CHARSET = "unicode";
String result = null;
try {
result = new String(/*太长省略*/);
index += BYTE_LENGTH * length;
} catch (UnsupportedEncodingException e) {
//略
}
return result;
}
}
接下来只要让Income,Salary,Investment 继承BaseBean,
实作getFields,(读设定档或是直接hard code在程式里)
再由外部程式依照所得阵列长度来初始化其中之一物件即可。
未来若是新增一个180 bytes的input,
只要新增一个子类别,
定义好自身的属性以及字段的顺序,
就可以很容易的扩充。
若是parse byte array的方式有变也只需更改父类别,
不会对子类别有太大的影响。