I want to write some different algorithms for different data structures(eg tree, list, array, ...). The methods of the data structures are 90% identical except for the method parameter.
public class BinaryTreeNode<T> {
public T key;
public BinaryTreeNode<T> leftChild;
public BinaryTreeNode<T> rightChild;
public boolean find(BinaryTreeNode<T> root, T key) { /* implementation */ }
}
public class ListItem<T> {
public T key;
public ListItem<T> next;
public boolean find(ListItem<T> root, T key) { /* implementation */ }
}
In order not to have to write each method individually I made an abstract DataStruct<T>
class
public abstract class DataStruct<T> {
/**
* finds the key in dataStruct
* @param dataStruct DataStruct to look for key
* @param key value of type T to find in dataStruct
* @return true if key is in dataStruct else false
*/
public abstract find(DataStruct<T> dataStruct, T key);
}
I let BinaryTreeNode<T>
and ListItem<T>
extend
DataStruct<T>
Now my problem is to access the class attributes. I solved it like this:
public class ListItem<T> extends DataStruct<T> {
public T key;
public ListItem<T> next;
@Override
public boolean find(DataStruct<T> listItem, T key) {
ListItem<T> tmpListItem = (ListItem<T>) listItem;
while(tmpListItem.next != null) {
if(tmpListItem.key == key)
return true;
}
}
}
But it does not feel well coded because I had to create a temporary ListItem<T>
to cast the DataStruct<T>
to access the class attributes of ListItem<T>
.
Is there a better way to do this?
Since the find
method is not a static
method, it doesn't make sense that it accepts a DataStruct<T>
object and performs the search on that object. It makes more sense to perform the search on itself, which eliminates the need to cast anything:
public boolean find(T key) {
ListItem<T> tmpListItem = this;
while(tmpListItem.next != null) {
if(tmpListItem.key.equals(key))
return true;
tmpListItem = tmpListItem.next;
}
}
Now, it some of your methods do require a DataStruct<T>
argument, and you require, for example, that the implementation of these methods in ListItem
accpet only a ListItem
, it will make sense to check the type of the input argument, throw an exception (or return false, or whatever makes sense) if the run-type is wrong, and perform the cast. This is a common practice in methods such as equals
, which accept an Object
and usually require that the run-time type be a specific type.
For example:
public boolean find(DataStruct<T> listItem, T key) {
if (!(listItem instanceof ListItem)) {
// decide whether to return false or throw an exception
}
ListItem<T> tmpListItem = (ListItem<T>) listItem;
...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.