在做中学的荣誉。以下是“机会”有待改进的建议:
元组只能存在一种(一旦设置了Typelock)。除非您诉诸于剪切粘贴重复使用(BirthdayTuple,DimensionsTuple,StreetAddressTuple等),否则这会损害希望使用多种元组类型的程序的可重用性和可伸缩性。考虑一个TupleFactory类,该类接受目标类型并创建一个元组生成器对象以生成元组。
没有记录“ null”作为元组中的值的有效性。我认为在设置Typelock之前,允许为null;但是设置了Typelock之后,代码将生成NullPointerException-这是不一致的。如果不允许使用,则构造函数应捕获它并禁止它(与Typelock无关)。如果允许,则整个代码(构造函数,equals,hashpre等)都需要进行修改以允许使用。
确定元组是否旨在成为不可变值对象。基于它缺乏设置方法的原因,我猜是这样。如果是这样,请小心“采用”传入的数组-
lastTuple=this.arr
。即使其为var arg构造函数,也可以直接使用数组调用该构造函数。该类采用数组(保留对其的引用),并且此后可以在类外部更改数组中的值。我将对数组进行浅表复制,但还要记录具有不可更改值(可以在元组外部更改)的元组的潜在问题。您的
equals
方法缺少空检查(if (obj == null) return false
)和类检查(obj instanceof Tuple
或this.getClass().equals(object.getClass())
)。平等习语有据可查。除非通过,否则无法查看元组的值
toString
。这样可以保护的值和整体不变性,但是我认为这限制了该类的用处。虽然我意识到这只是一个例子,但我不希望将此类用于生日/日期之类的东西。在具有固定对象类型的解决方案域中,真实类(例如Date)要好得多。我可以想象此类在元组是第一类对象的特定领域中很有用。
编辑
一直在考虑这一点。这是我对一些代码的看法(在github
+
tests上):
===Tuple.java===package com.stackoverflow.tuple;public interface Tuple { public TupleType getType(); public int size(); public <T> T getNthValue(int i);}===TupleType.java===package com.stackoverflow.tuple;public interface TupleType { public int size(); public Class<?> getNthType(int i); public Tuple createTuple(Object... values); public class DefaultFactory { public static TupleType create(final Class<?>... types) { return new TupleTypeImpl(types); } }}===TupleImpl.java (not visible outside package)===package com.stackoverflow.tuple;import java.util.Arrays;class TupleImpl implements Tuple { private final TupleType type; private final Object[] values; TupleImpl(TupleType type, Object[] values) { this.type = type; if (values == null || values.length == 0) { this.values = new Object[0]; } else { this.values = new Object[values.length]; System.arraycopy(values, 0, this.values, 0, values.length); } } @Override public TupleType getType() { return type; } @Override public int size() { return values.length; } @SuppressWarnings("unchecked") @Override public <T> T getNthValue(int i) { return (T) values[i]; } @Override public boolean equals(Object object) { if (object == null) return false; if (this == object) return true; if (! (object instanceof Tuple)) return false; final Tuple other = (Tuple) object; if (other.size() != size()) return false; final int size = size(); for (int i = 0; i < size; i++) { final Object thisNthValue = getNthValue(i); final Object otherNthValue = other.getNthValue(i); if ((thisNthValue == null && otherNthValue != null) || (thisNthValue != null && ! thisNthValue.equals(otherNthValue))) { return false; } } return true; } @Override public int hashCode() { int hash = 17; for (Object value : values) { if (value != null) { hash = hash * 37 + value.hashCode(); } } return hash; } @Override public String toString() { return Arrays.toString(values); }}===TupleTypeImpl.java (not visible outside package)===package com.stackoverflow.tuple;class TupleTypeImpl implements TupleType { final Class<?>[] types; TupleTypeImpl(Class<?>[] types) { this.types = (types != null ? types : new Class<?>[0]); } public int size() { return types.length; } //WRONG //public <T> Class<T> getNthType(int i) //RIGHT - thanks Emil public Class<?> getNthType(int i) { return types[i]; } public Tuple createTuple(Object... values) { if ((values == null && types.length == 0) || (values != null && values.length != types.length)) { throw new IllegalArgumentException( "Expected "+types.length+" values, not "+ (values == null ? "(null)" : values.length) + " values"); } if (values != null) { for (int i = 0; i < types.length; i++) { final Class<?> nthType = types[i]; final Object nthValue = values[i]; if (nthValue != null && ! nthType.isAssignableFrom(nthValue.getClass())) { throw new IllegalArgumentException( "Expected value #"+i+" ('"+ nthValue+"') of new Tuple to be "+ nthType+", not " + (nthValue != null ? nthValue.getClass() : "(null type)")); } } } return new TupleImpl(this, values); }}===TupleExample.java===package com.stackoverflow.tupleexample;import com.stackoverflow.tuple.Tuple;import com.stackoverflow.tuple.TupleType;public class TupleExample { public static void main(String[] args) { // This pre probably should be part of a suite of unit tests // instead of part of this a sample program final TupleType tripletTupleType = TupleType.DefaultFactory.create( Number.class, String.class, Character.class); final Tuple t1 = tripletTupleType.createTuple(1, "one", 'a'); final Tuple t2 = tripletTupleType.createTuple(2l, "two", 'b'); final Tuple t3 = tripletTupleType.createTuple(3f, "three", 'c'); final Tuple tnull = tripletTupleType.createTuple(null, "(null)", null); System.out.println("t1 = " + t1); System.out.println("t2 = " + t2); System.out.println("t3 = " + t3); System.out.println("tnull = " + tnull); final TupleType emptyTupleType = TupleType.DefaultFactory.create(); final Tuple tempty = emptyTupleType.createTuple(); System.out.println("ntempty = " + tempty); // Should cause an error System.out.println("nCreating tuple with wrong types: "); try { final Tuple terror = tripletTupleType.createTuple(1, 2, 3); System.out.println("Creating this tuple should have failed: "+terror); } catch (IllegalArgumentException ex) { ex.printStackTrace(System.out); } // Should cause an error System.out.println("nCreating tuple with wrong # of arguments: "); try { final Tuple terror = emptyTupleType.createTuple(1); System.out.println("Creating this tuple should have failed: "+terror); } catch (IllegalArgumentException ex) { ex.printStackTrace(System.out); } // Should cause an error System.out.println("nGetting value as wrong type: "); try { final Tuple t9 = tripletTupleType.createTuple(9, "nine", 'i'); final String verror = t9.getNthValue(0); System.out.println("Getting this value should have failed: "+verror); } catch (ClassCastException ex) { ex.printStackTrace(System.out); } }}===Sample Run===t1 = [1, one, a]t2 = [2, two, b]t3 = [3.0, three, c]tnull = [null, (null), null]tempty = []Creating tuple with wrong types: java.lang.IllegalArgumentException: Expected value #1 ('2') of new Tuple to be class java.lang.String, not class java.lang.Integer at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:32) at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:37)Creating tuple with wrong # of arguments: java.lang.IllegalArgumentException: Expected 0 values, not 1 values at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:22) at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:46)Getting value as wrong type: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:58)


