How to refactor this code? - java

Please suggest in refactoring this code.
Avoid code duplication, mutiple If's
public FormDataDTO getDataForFieldFormCHrzntalField(Field field) {
FormDataDTO formDataDTO = new FormDataDTO();
CHrzntalField cHrzntalField = (CHrzntalField) field;
for (int j = 0; j < cHrzntalField.getFieldCount(); j++) {
Field sField = cHrzntalField.getField(j);
if (sField instanceof LabelField) {
LabelField labelField = sField;
String fieldName = labelField.getText();
System.out.println("The Label field name is " + fieldName);
formDataDTO.setFieldName(fieldName);
} else if (sField instanceof CTextFieldBorder) {
CTextFieldBorder cTextFieldBorder = (CTextFieldBorder) sField;
Field ssField = cTextFieldBorder.getField(0);
if (ssField instanceof TextField) {
TextField textField = ssField;
System.out.println("Inside TextField---- "
+ textField.getText());
formDataDTO.setFieldType("TextField");
formDataDTO.setSelectedValue(textField.getText());
} else if (ssField instanceof DateField) {
DateField dateField = ssField;
String dateString = dateField.toString();
System.out.println("dateString " + dateString);
formDataDTO.setFieldType("Date");
formDataDTO.setSelectedValue(dateString);
}
} else if (sField instanceof CChoiceField) {
CChoiceField cChoiceField = (CChoiceField) sField;
int i = cChoiceField.getSelectedIndex();
String selectedValue = cChoiceField.getChoice(i);
System.out.println("Choice " + selectedValue);
formDataDTO.setFieldType("Combo");
formDataDTO.setSelectedValue(selectedValue);
} else if (sField instanceof CheckboxField) {
CheckboxField checkboxField = (CheckboxField) sField;
boolean checkStatus = checkboxField.getChecked();
System.out.println("Check box field " + checkStatus);
formDataDTO.setFieldType("Checkbox");
String status = new Boolean(checkStatus).toString();
formDataDTO.setSelectedValue(status);
}
}
return formDataDTO;
}

First step is to create a unit test verifying the behavior of this method. Secondly, "Tell, don't ask" is a principle of good OO design, so it would be good if you could refactor the Field type and its subclasses, to implement a method that allows them to set the necessary information on the FormDataDTO.

You could start by pulling each case block (the code inside the if / else if blocks) into their own methods. There isn't a lot of repetition that I can see, it's just trying to do too much in one method.

You could apply a strategy pattern from the looks of it;
create an interface with methods you call on all Fields, say FieldHandler
initialise a map from ClassName to FieldHandler containing implementations per field type you need to cover (like LabelFieldHandler, DateFieldHandler, etc.)
in your function doXXX instead of using instanceOf to execute variantions per field type, look up the corresponding handler in your map and delegate the call to the handler.
pseudo code:
field = getField(j);
handler = handlerMap.get(field.className);
if (null == handler) {
// error unknown field type
} else {
handler.setFormData(field, formDataDTO);
}

Add a new abstract method in Field
public class Field {
public abstract void updateFormData(FormDataDTO formDataDTO);
}
and then, implements it in each subclass of Field.
Finally, your code becomes:
public FormDataDTO getDataForFieldFormCHrzntalField(Field field) {
FormDataDTO formDataDTO = new FormDataDTO();
CHrzntalField cHrzntalField = (CHrzntalField) field;
for (int j = 0; j < cHrzntalField.getFieldCount(); j++) {
Field sField = cHrzntalField.getField(j);
sField.updateFormData(formDataDTO);
}
return formDataDTO;
}

You need to dispatch on field type. There are various ways of doing this:
Use if statements that explicitly test the class.
Make all fields implement an interface, implement that interface appropriately for each field type, and then call the interface.
Use a map to look-up the appropriate action for the class.
Option 1 is what you are doing now; 2 is what Stroboskop mentions; 3 is called the strategy pattern by rsp. 1 is a bit of a mess, as you can see. 2 couples the work of the method above with the fields, while 3 doesn't. Which of these (2 or 3) to chose depends on your particular case. An advantage of (2) is that you don't forget to write the code for each new field (because you'll get a compiler error if you do forget). An advantage of (3) is that if you want to do this kind of thing many times, the fields can get cluttered. Also, (2) requires that you have access to the fields code.
It's worth noting that if you were using Scala rather than Java some of the problems with (2) are avoided with traits (and that it also has nicer syntax for (1) with pattern matching).
personally I would prefer (2) if possible - perhaps implementing it with delegation. The only real advantage of (3) over (1) is that the code is neater - and there's a little extra type safety.

You should use method overloading to avoid instanceof calls. Each if (sField instanceof ...) should be moved to a separate method taking the desired type as parameter.

Related

Copy fields across objects of different type in gRPC

Suppose I have two proto buffer types:
message MessageType1 {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType3 field3 = 3;
}
message MessageType2 {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType4 field4 = 3;
}
Then in Java I would like to be able to use one object as a template to another:
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.usingTemplate(message1) // sets field1 & field2 only
.setField4(someValue)
.build()
instead of
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.setField1(message1.getField1())
.setField2(message1.getField2())
.setField4(someValue)
.build()
Why do I need this? My gRPC service is designed to take incoming data of one type (message1) which is almost identical to another message of a different type (message2) -- which needs to be sent out. The amount of identical fields is huge and copy code is mundane. Manual solution also has a disadvantage of a miss if a new field gets added.
There exists a template method (object.newBuilder(template)) which allows templating object of the same type, but how about templating between different types?
I could, of course, write a small reflection utility which inspects all members (methods?) and manually copies data over, but generated code looks discouraging and ugly for this sort of quest.
Is there any good approach to tackle this?
It turned out to be not so complicated. I wrote a small utility which would evaluate and match FieldDescriptors (something that gRPC generates). In my world it is enough to match them by name and type. Full solution here:
/**
* Copies fields from source to dest. Only copies fields if they are set, have matching name and type as their counterparts in dest.
*/
public static void copyCommonFields(#Nonnull GeneratedMessageV3 source, #Nonnull com.google.protobuf.GeneratedMessageV3.Builder<?> destBuilder) {
Map<FieldDescriptorKeyElements, Descriptors.FieldDescriptor> elementsInSource = Maps.uniqueIndex(source.getDescriptorForType().getFields(), FieldDescriptorKeyElements::new);
Map<FieldDescriptorKeyElements, Descriptors.FieldDescriptor> elementsInDest = Maps.uniqueIndex(destBuilder.getDescriptorForType().getFields(), FieldDescriptorKeyElements::new);
// those two above could even be cached if necessary as this is static info
Set<FieldDescriptorKeyElements> elementsInBoth = Sets.intersection(elementsInSource.keySet(), elementsInDest.keySet());
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : source.getAllFields().entrySet()) {
Descriptors.FieldDescriptor descriptor = entry.getKey();
FieldDescriptorKeyElements keyElements = new FieldDescriptorKeyElements(descriptor);
if (entry.getValue() != null && elementsInBoth.contains(keyElements)) {
destBuilder.setField(elementsInDest.get(keyElements), entry.getValue());
}
}
}
// used for convenient/quick lookups in a Set
private static final class FieldDescriptorKeyElements {
final String fieldName;
final Descriptors.FieldDescriptor.JavaType javaType;
final boolean isRepeated;
private FieldDescriptorKeyElements(Descriptors.FieldDescriptor fieldDescriptor) {
this.fieldName = fieldDescriptor.getName();
this.javaType = fieldDescriptor.getJavaType();
this.isRepeated = fieldDescriptor.isRepeated();
}
#Override
public int hashCode() {
return Objects.hash(fieldName, javaType, isRepeated);
}
#Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof FieldDescriptorKeyElements)) {
return false;
}
FieldDescriptorKeyElements other = (FieldDescriptorKeyElements) obj;
return Objects.equals(this.fieldName, other.fieldName) &&
Objects.equals(this.javaType, other.javaType) &&
Objects.equals(this.isRepeated, other.isRepeated);
}
}
Answering your specific question: no, there is no template based way to do this. However, there are some other ways to get the same effect:
If you don't care about performance and the field numbers are the same between the messages, you can serialize the first message to bytes and deserialize them back as the new message. This requires that all the fields in the first message must match the type and id number of those in the second message (though, the second message can have other fields). This is probably not a good idea.
Extract the common fields to another message, and share that message. For example:
proto:
message Common {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType3 field3 = 3;
}
message MessageType1 {
Common common = 1;
// ...
}
message MessageType2 {
Common common = 1;
// ...
}
Then, you can share the messages in code:
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.setCommon(message1.getCommon())
.build();
This is the probably the better solution.
Lastly, as you mentioned, you could resort to reflection. This is probably the most verbose and slowest way, but it would allow you the most control (aside from manually copying over the fields). Not recommended.

Enumeration help/advice - java

Is it possible to use an enumeration in the following circumstance:
Let’s say you have a certain amount of predefined 'read types'. Example read types could be: Diagnostic, KWH, MaxDemand, OnPeak, etc. And for each of these read types, there’s a ‘TIMTagNumber’ which is essientally a protocol for retrieving each predefined read type.
For example, TIMTagNumber 1100 would retrieve the read type Diagnostic
TIMTagNumber 1300 would retrieve the read type KWH.
The problem is that a predefined read type can sometimes be retrieved by more than one TIMTagNumber.
I want to create an enumeration ReadType that would define each read type and all TIMTagNumbers that can be used to retrieve that read.
Can you use an enumeration in this way?
public enum ReadType{
KWH(1300)
Diagnostic(1100)
ReadType3(1400, 1401) // This read can be retrieved by both 1400 and 1401
}
If an enumeration is not the way to go, is there an elegant or efficient way to define these read types? The overall desired outcome of all this essientally is being recognizing what type of read it is based on the TIMTagNumbers.
I.E. Given 1400 OR 1401 you would know that it's 'ReadType3'.
Can you do this? Yes. Whether it's the right decision will depend on whether you want to couple these TIMTagNumbers to the read type. If not, a simple Map<Integer, ReadType> will probably suffice.
Here's how you could do it:
public static enum MyEnum {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private Set<Integer> timTagNumbers;
MyEnum(Integer... timTagNumbers) {
this.timTagNumbers = new HashSet<Integer>(Arrays.asList(timTagNumbers));
//add check to make sure that values are unique across all instances
}
public static MyEnum forTIMTagNumber(int num) {
for ( MyEnum readType : values() ) {
if ( readType.timTagNumbers.contains(num) ) {
return readType;
}
}
throw new NoSuchElementException("No ReadType matching TIMTagNumber " + num);
}
}
//...
int timTagNumber = 1400;
ReadType readType = ReadType.forTIMTagNumber(timTagNumber);
As I said above, this style works well when the data and the enum types are intrinsically coupled already. It would not be good for when the enum type is decoupled from the mapped values (e.g. the values are used for one of many ways of serializing the enum) or if the values are configuration-specific or even dynamic (e.g. if they were prices on an item). In these cases it is usually best to externalize this mapping in an EnumMap or Map.
public enum ReadType {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private int[] timTagNumbers;
private ReadType(int ... numbers) {
this.timTagNumbers = numbers;
}
public int[] getTimTagNumbers() {
return timTagNumbers;
}
public static ReadType forTimTagNumber(int n) {
for (ReadType type : values()) {
if (Arrays.binarySearch(type.timTagNumbers, n) != -1) {
return type;
}
}
throw new NoSucheElementException(); // if not found
}
With this you can do
int[] timTagNumbers = ReadType.Diagnostic.getTimTagNumbers(); // [ 1100 ]
and
ReadType type3 = ReadType.forTimTagNumber(1401); // ReadType.ReadType3
You can indeed use enumerations in that way, but your example is missing a private field and a constructor.
Something like:
public enum Bla{
CASE1(100),CASE2(200);
private int amount;
private Bla(int amount) {
this.amount = amount;
}
public Bla getByValue(int value){
switch (value) {
case 100: return CASE1;
case 200: return CASE2;
}
return null;
}
}
I've included a "reverse lookup" method that returns an Enum given the value.
The main advantage is that you can have the rest of your code using "Bla" instead of int's which will guarantee type-safety on your operations, basically, it'll make impossible to pass an invalid int value as a method parameter (and you can use switch statements over enums too, and that's pretty awesome in some usage scenarios).
EDIT: I noticed after I posted that you need more then one int to specify the Enum, but the same logic applies, with the due changes in the methods, of course.
You could do something like the following, when you supply values in the parentheses where the enum variable is declared, it is calling the constructor of the enum. You need to create a different method in the enum itself to get the enum type from the integer value. See below.
public enum ReadType {
KWH(), DIAGNOSTIC(), READTYPE3();
public ReadType getReadType(int num) {
ReadType toReturn = KWH;
switch (num) {
case 1300:
toReturn = KWH;
break;
case 1100:
toReturn = DIAGNOSTIC;
break;
case 1400:
toReturn = READTYPE3;
break;
case 1401:
toReturn = READTYPE3;
break;
}
return toReturn;
}
If you can impose some restrictions like no more than 2 tags can be associated with a read type and each tag is no greater than 2^15, then you can store the two numbers into 1 integer. See this S/O post for more details.

Searching an ArrayList

I currently have 3 classes, a main class containing a GUI, and the fnameTxtField, a customer class containing the data, and a customerList class which gathers the data from the customer class, and puts it into an array list.
Quick fix: Refactor your method to have the following signature public void searchCustomer(String text) { ... } and call it with
searchCustome(fnameTxtField.getText()).
Then you could use the variable "text" in your method, so the line
if (search.returnFamilyName().equals(fnameTxtField.getText))
changes to
if (search.returnFamilyName().equals(text))
(Or don't have any parameters at all and add the [probably] missing parentheses to fnameTxtField.getText)
Where you are using fnameTxtField.getText, Java is expecting you to declare a method parameter (kind of like declaring a variable). A parameter is information that your method is told about for one particular execution, instead of having to find out on its own.
So you are right in thinking you want something like this:
public void searchCustomer(String familyName) {
for (int i = 0; i < customer.returnID(); i++) {
customer search = search.get(i);
if (search.returnFamilyName().equals(familyName)) {
System.out.println("Index: " + i);
//removed return i;
return;
}
}
}
Then at the point of invocation (method call) specify that you want to use the value in your text field:
//...
searchCustomer(fnameTxtField.getText());

Loop for Enums in Java

I have some enums like this:
public enum Classification {
UNKNOWN("Unknown"),
DELETION("Deletion"),
DUPLICATION("Duplication"), ....
but some of them have like 20 members, so currently in code I deal with them with huge if/else blocks like this:
int classification= rs.getInt("classification");
if (classification == Classification.UNKNOWN.ordinal()) {
variant.setClassification(Classification.UNKNOWN);
} else if (classification == Classification.DELETION.ordinal()) {
variant.setClassification(Classification.DELETION);
( rs is from JDBC tho).
Does Java have a better way this these big if/else blocks to do what I am doing? some sorting of looping through it?
You could use Enum#values() to get all enum values in an array. The ordinal maps 1:1 to the array index. Add the following method fo your Classification enum:
public static Classification of(int ordinal) {
if (0 <= ordinal && ordinal < values().length) {
return values()[ordinal];
}
throw new IllegalArgumentException("Invalid ordinal " + ordinal);
}
and use it as follows
Classification classification = Classification.of(rs.getInt("classification"));
// ...
However, using enum's ordinal for this is not the best practice. What if some developer rearranges the enum's values or adds/removes values? Even the javadoc warns that it has usually no use for developers. Rather give each enum value a fixed identifier. You could pass it in as an additional argument of the enum constructor argument. You could even use enum's String representation for that.
UNKNOWN(1, "Unknown"),
DELETION(2, "Deletion"),
DUPLICATION(3, "Duplication"),
// ...
Then use that value for DB instead and modify the of() method to walk through them in a foreach loop:
public static Classification of(int id) {
for (Classification classification : values()) {
if (classification.id == id) {
return classification;
}
}
throw new IllegalArgumentException("Invalid id " + id);
}
If the db value is the ordinal of the Enum then:
int classification= rs.getInt("classification");
variant.setClassification(Classification.values()[classification]);
I'll leave bounds checking as an exercise for the reader.
You can loop through an enumeration’s values via the object the someEnum.values() method returns:
for (Classification clz : Classification.values()) doSomethingWith(clz);
found here
I don’t know how exactly I can help you, since i don’t know what rs.getInt(String) does.
It seems to give back an Integer representing a enum value of Classification, but why?
Use variant.setClassification(YourEnumClassHere.values()[classification]). Enum.values() returns an array of all the declared enums in that class.
Instead of storing ordinal, you can store the name and use the valueOf method to convert the String back to your Enum type.
If you willing and able to store a string representation (this is a good technique) of the ENUM in your database, see Reference from Gareth Davis in comments above. If you are unwilling and/or unable to store a string representation and must continue with an ordinal representation, I suggest that a Map is called for. Here is some example code:
public class EnumMap
{
private enum FistSounds
{
Blam, Kapow, Zowie, Biff;
private static Map<Integer, FistSounds> ordinalMap = new HashMap<Integer, FistSounds>();
static
{
ordinalMap.put(Blam.ordinal(), Blam);
ordinalMap.put(Kapow.ordinal(), Kapow);
ordinalMap.put(Zowie.ordinal(), Zowie);
ordinalMap.put(Biff.ordinal(), Biff);
}
public static final FistSounds getByOrdinal(final int enumIndex)
{
return ordinalMap.get(enumIndex);
}
}
public static void main(String[] args)
{
FistSounds fistSound;
for (int index = -1; index < 5; ++index)
{
fistSound = FistSounds.getByOrdinal(index);
System.out.print("Ordinal: ");
System.out.print(index);
System.out.print(", FistSound: ");
System.out.println(fistSound);
}
}
}
I'd recommend using a switch statement, if the logic to execute is different for each case....
do as #Gareth Davis instructs and then just have a switch statement and handle each case as required.
Enums are also eligible to be used in switch statements see here

refactoring multiple if-else conditionals in a method

I am in the process of refactoring my existing code. It actually works fine, but it is a bit cluttered with multiple if-else conditionals checking the value of one variable and change the value of a second variable to an updated value taken from a fixed enumeration structure.
else if (var1 == 'valueX')
{
if (var2 == MyEnum.A)
var2 = MyEnum.B;
else if (var2 == MyEnum.B)
var2 = MyEnum.C;
else if (var2 == MyEnum.C)
var2 = MyEnum.D;
else if (var2 == MyEnum.D)
var2 = MyEnum.A;
}
else if (....)
{
..similar block of conditionals
}
I am a bit confused as to what is the best way to refactor and clean-up this code. Would you suggest the use of a switch perhaps? Or something more elegant?
Thanks in advance!
The classic answer to refactoring conditionals is Replace Conditional With Polymorphism. In this case, if each of MyEnum knew what its successor was, you could simply say (in the 'valuex' case: var2 = var2.successor. For var1 - if it could be an object that implemented an interface that knew how to handle whatever you're doing inside the loop, and each implementing class knew what it, specifically, should do... Well, you'd be done.
Update:
And here's a dandy little successor function in a test case:
public class EnumTest extends TestCase {
private enum X {
A, B, C;
public X successor() {
return values()[(ordinal() + 1) % values().length];
}
};
public void testSuccessor() throws Exception {
assertEquals(X.B, X.A.successor());
assertEquals(X.C, X.B.successor());
assertEquals(X.A, X.C.successor());
}
}
At least with J2SE 1.5 forward, you can give enums extra attributes. This means you might be able to replace that entire string of if-else with something that looks like
var2 = var1.getNextInSequence();
Now, in this case, it looks like you would want the attribute to be a reference to another enum, which adds some wrinkles, for example you can't forward reference enums when you initialize them, but there might be a workable solution for you this way.
When the attributes aren't other instances of the same enum, this kind of thing will work:
public enum Animal {
FOX(4),
CHICKEN(2),
WORM(0);
private int countLegs;
Animal(int n) {
countLegs = n;
}
public int getLegCount() {
return countLegs;
}
// .. more getters setters etc
}
But when the enum is self-referential, you have to be careful about the order of declaration of your instances. I.e., this will have some issues:
public enum Animal {
FOX(4, CHICKEN), // 'CHICKEN' doesn't exist yet
WORM(0, null),
CHICKEN(2, WORM); // this actually will compile
private int countLegs;
private Animal eatsWhat;
Animal(int n, Animal dinner) {
countLegs = n;
eatsWhat = dinner;
}
public int getLegCount() {
return countLegs;
}
// .. getters, setters, etc
}
So if you had need of a circular set of references among the enums, you'd have to work something else out, but if not, you could use this technique, though you may have to order your enum instances just so to make it work.
You can use a simple map:
enum MyEnum { A, B, C };
Map<MyEnum, MyEnum> VALUE_X = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.B);
put(MyEnum.B, MyEnum.C);
...
}};
// define another kind of ordering
Map<MyEnum, MyEnum> VALUE_Y = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.D);
put(MyEnum.B, MyEnum.A);
...
}};
This way, the logic of the next var2 value isn't hard-coded in the enum itself, and can be dependant of context (i.e. value of var1):
if ("valueX".equals(var1)) { // use equals() instead of == for Strings
var2 = VALUE_X.get(var2);
}
else if ("valueY".equals(var1)) {
var2 = VALUE_Y.get(var2);
}

Categories