简体   繁体   中英

Code duplication (or not) - JAVA

I have a situation of code duplication (or is it ? ) and I don't know how to avoid it , but still keep clarity in my code.

Let me hugely oversimplify the situation:

// let's say I have a interface Entity

interface Entity {

    public Entity add (Entity operand);

}

// And two classes that implement this interface

class MyInteger implements Entity {

    private int value;

    public Entity add (Entity operand)
    {
         // here I have to manage the situation distinctly if operand is a MyInteger or MyString

    }

}

class MyString implements Entity {

    private String value;

    public Entity add (Entity operand )
    {

    }
}

Now, my problem is that the method add in MyString is bassicly the same as the method add in MyInteger. Keep in mind that I have way more types than the two mentioned here, and for some the method add is not the same.

Is this code duplication? And if so, is there a way to avoid it? Cause I can't seem to think of one.

Also , in the add method, how can I switch between the various types operand can have without using if (instanceof ) statements?

Look up the Template pattern. You could refactor and add an Abstract class for any duplicate code. If this is specific to two classes you could have just those two classes extend the Abstract class.

To avoid instanceof I'm not sure what would be best but you could chain an extra method specific to an entity class which then calls the super/abstract class if necessary.

Lastly, investigate what possibilities are offered by generics.

Sounds like you need the visitor or double-dispatch mechanism.

Your add(Entity operand) method has to decide what to do based on the operand passed, and so you can achive this by calling back on the operand. eg

// in MyInteger
public Entity add(Entity operand) {
   operand.addInteger(this);
}

// in MyString
public Entity add(Entity operand) {
   operand.addString(this);
}

Note that the implementation of the above changes upon the type called. By redirecting back to the operand your call path is determined by the entity originally called upon and the operand used.

Each Entity would have to implement addInteger(MyInteger p) , addString(MyString p) etc. but at this stage you have concrete types to work with and can determine trivially what to do.

Note that you're not having to use instanceof or similar. The above is typesafe and complete. eg adding a new operand type will result in an obvious set of refactorings.

您可以使用抽象类并为其提供具体的add方法。

So far I do not see problems in your approach.

As entity is an instance, you can solve code duplication by:

  • Simply ignoring it and do duplication because it will give you a clean solution. If you have only a few cases where such duplication occur, it may be better to implement it in this way.

  • As already said, implement an abstract class eg AbstractEntity implementing all methods once as protected member methods and declare MyInteger and MyString as subclasses.

  • Go further with subclassing, think over what methods are needed for which entity and build up a tree of subclasses. Caution: This will hamper further adjustments if you cannot do careful design.

  • Use an utility class: class with public static methods and a private constructor to implement the functionality to need.

How to find out the type of entity:

  • Use instanceof (ok, it IS ugly)
  • Implement methods in the interface returning the type as Enum or test for properties: getType() == STRING or isString()
  • Implement methods in the interface doing what you wish: checkIfStringAndAddIt().

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM