7

Now I have an existing class that I would like to refactor to be an Enum. The class currently extends another class which is from external library. As I still would like to benefit from some logics from that extended class meanwhile would like to refactor. How should it be done?

In Java, an enum class cannot extend another class whereas it can implement interface. Or is it already wrong for the idea of refactoring it to be an Enum? Let me show it in the example code below.

Assume an existing class Existing is extending another class Parent and the Parent class is from an external library and it is NOT an interface.

class Existing extends Parent{
    public static final Existing A = new Existing(...);
    ....
    public static final Existing Z = new Existing(...);

    public Existing(Srting attr1, String attr1){
        super(attr1, attr2);
    }

    public Existing(String attr1){
       super(attr1);
    }
}

The idea is to have those static final fields to be Enums, e.g.:

enum NewDesign{
     A(attr1, attr2),
     B(attr1),
     C(attr1, attr2)
     //...;
     //constructor etc.
     //...
}

and possibly when needed, with new extra attr added as below:

enum NewDesign{
  A(attr1, attr2, newAttr),
  B(attr1, newAttr),
  C(attr1, attr2, newAttr),
  //...
  //constructor etc.
  //...
}
Raedwald
  • 46,613
  • 43
  • 151
  • 237
qwop72
  • 81
  • 4
  • 1
    I think your current code is fine, why do you need an enum? – Sweeper Jul 24 '19 at 07:18
  • Hi! The need comes acutally when I would like to add the extra attribute. Let's say, an category flag, to identify the kind of object. In this case I would think it a useful scenario using Enum. Isnt it? – qwop72 Jul 24 '19 at 07:21
  • 2
    https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance - inheritance may not be the best choice in the first place if what you want is to _benifit from some logics from that extended class_. – Lars Christian Jensen Jul 24 '19 at 07:22
  • 3
    In either case you have to add an extra argument to the constructor call, don't you? Can you [edit] the question to show how difficult it is to add a new attribute (field?) to a class? – Sweeper Jul 24 '19 at 07:24
  • @Sweeper sorry I forget to @ you, and if I do not refactor to an Enum, I would need to pass it through the constructor after the super(). and I think is kind of against the inheritance? – qwop72 Jul 24 '19 at 07:26
  • thanks for both of your comments! I will read through that and possibly edit the question in a better form – qwop72 Jul 24 '19 at 07:27
  • 1
    Agree with composition over inheritance here. Since OP is reliant on an external library, they cannot control how updates will affect the classes they extend from. Composition mitigates those potential shakeups somewhat. – Austin Schaefer Jul 24 '19 at 07:28
  • 1
    @qwop72 And don't rush to accept an answer, your question is good and it may gain popularity and someone could come up with a nicer solution... (at least, I am interested to see a different approach :)) – Andrew Tobilko Jul 24 '19 at 07:51

3 Answers3

5

If the main change that you need is to create an enum to get rid of static final fields, the easiest way to go about it is to create a different, enum type with initialized instances:

enum ExistingEnum {
    A("attr1", "attr2"), 
    Z("attr");

    private final Existing existing;

    ExistingEnum(String attr1) {
        this.existing = new Existing(attr1);
    }

    ExistingEnum(String attr1, String attr2) {
        this.existing = new Existing(attr1, attr2);
    }

    public Existing getExisting() {
        return existing;
    }
}

Depending on how you're using your Existing class currently, you may still be able to change it to an enum. In the following example, I expose an instance of Parent on the enum, assuming code using Existing can be changed to call Existing.A.getParent().parentMethod()...

enum Existing {
    A("attr1", "attr2"),

    Z("attr");

    private final Parent existing;

    Existing(String attr1) {
        this.existing = new ParentImpl(attr1);
    }

    Existing(String attr1, String attr2) {
        this.existing = new ParentImpl(attr1, attr2);
    }

    public Parent getParent() {
        return existing;
    }

    // only needed if logic is overridden
    private static class ParentImpl extends Parent {
        public static final Existing A = "";
        public static final Existing Z = "";

        public ParentImpl(String attr1, String attr2) {
            super(attr1, attr2);
        }

        public ParentImpl(String attr1) {
            super(attr1);
        }
    }
}
ernest_k
  • 44,416
  • 5
  • 53
  • 99
3

I think you can use composition:

public class Parent {
    private String attr1;
    private String attr2;

    public Parent(String attr1, String attr2) {
        this.attr1 = attr1;
        this.attr2 = attr2;
    }

    public void doSomething() {
        // do something.
    }
}

// compose the class Parent
public enum NewDesign {
    A("attr1", "attr2"),
    B("attr1", "attr2")
    ;

    private Parent parent;

    NewDesign(String attr1, String attr2) {
        this.parent = new Parent(attr1, attr2);
    }
    public void func() {
        parent.doSomething();
    }
}
Shepherd
  • 59
  • 3
2

As I still would like to benefit from some logic from that extended class meanwhile would like to refactor.

Inheritance isn't the only one way you can benefit from the logic written in the library class. Composition (having a Parent as a field in Existing) may work.

Now I have an existing class that I would like to refactor to be an Enum.

Why enum? Your Existing class has two constructors meaning that you expect new instances to be created regardless of the already defined objects A...Z. It isn't the idea behind enums.

and possibly when needed, with new extra attr added

It can be tedious to refactor all the constants when a new attribute emerges. You are going to modify the class as soon as a new attribute is added. It doesn't look sound to me, and it kinda violates the open-closed principle - you aren't really open for extension with enums.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • 1
    I see your points. However, the Composition approach in this case drops the feature of Interitance, as the Existing is no long IS-A relation to the Parent? In turn, the Existing is used widely in the project benefiting as a child to the Parent; Regarding the other two points, I would guess a new architectual design is needed, though it seems to be complex in the project as I can understand by far. And yes, you are totally corret when it comes to the extra attribute and open-close principle, hmm...bad design in the begining perhaps :/ – qwop72 Jul 24 '19 at 08:50