Freewind
Freewind

Reputation: 198298

Enums vs Subclasses, which is Object-oriented design?

This is the code I wrote as a length-calculator for lengths with different kinds of unit. I wanted it to design it in Object-oriented.

public class Length {

    private final double value;
    private final Unit unit;

    public Length(double value, Unit unit) {
        this.value = value;
        this.unit = unit;
    }

    @Override
    public boolean equals(Object obj) {
        Length length = (Length) obj;
        return this.unit.toMM(this.value) == length.unit.toMM(length.value);
    }

    public Length add(Length added) {
        return new Length(this.unit.toMM(this.value) + added.unit.toMM(added.value), Unit.mm);
    }

    public Length subtract(Length another) {
        return new Length(this.unit.toMM(this.value) - another.unit.toMM(another.value), Unit.mm);
    }

}

enum Unit {
    m(1000), cm(10), mm(1);
    private final int rate;

    Unit(int rate) {
        this.rate = rate;
    }

    public double toMM(double value) {
        return rate * value;
    }
}

I use the enum Unit and let different units m/cm/mm as its members.

But I read this article about "OOP vs Non-OOP", it has a similar example which is marked as Non-OOP:

public class Person {

    private boolean _male; // true means male, false means female.

    public Person (boolean genderFlag) {
        _male = genderFlag;
    }

    public String getGender () {
        return _male? "male": "female";
    }
}

Which is not an enum, but the approach is quite similar, use some state internally to represent different types.

And it gives the OOP example using subclasses:

public abstract class APerson {
    public abstract String getGender();
}

public class Man extends APerson {
    public String getGender() {
        return "male";
    }
}

public class Woman extends APerson {
    public String getGender() {
        return "female";
    }
}

Apply to his ideas, I think my code should be re-written as:

interface Unit {
    public double toMM(double value);
}

public class Meter extends Unit {
    public double toMM(double value) {
        return 1000 * value;
    }
}

public class Centimeter extends Unit {
    public double toMM(double value) {
        return 10 * value;
    }
}

public class Millimeter extends Unit {
    public double toMM(double value) {
        return value;
    }
}

I can feel some differences between the two designs of my code, but still can't tell exactlly what it is.

Some questions:

  1. Is the first version with enum not considered as OOP?
  2. What's the real benifit of the second version with subclasses?
  3. Should we always considered the second version for such cases?

Upvotes: 4

Views: 2553

Answers (3)

achin
achin

Reputation: 169

I don't have the privilege to start commenting and hence writing my opinion in answer section.

IMO, what you are doing is the right thing. Using enums, you are using the ability to vary peculiarities (rate in your example) within the enum variables. Hence you no longer require if else condition as we do in person example. Also, by using enums you have made the code consice and do not inflict your code by class explosion.

To answer your q: (a) it is considered oops (b) you can use second methodology when you don't know the number of objects before hand. I.e. if we know that people can come up with a new child class tomorrow. In your case, length can be measured in mm, cm and so on, and the number of these parameters are known before hand. And hence it is perfectly good to code it in that manner. (c) depends on how you wish to design. Second way is correct too.

Upvotes: 2

Mike
Mike

Reputation: 542

  1. Is the first version with enum not considered as OOP?

No, the first version is an object oriented design. The latter, however, is certainly more object oriented, taking advantage of inheritance to determine a behavioral characteristic.

Based on that article you mentioned, I would say that the author thinks that the former is not an object oriented design, but you'll get a plethora of answers on this subject; you've been warned.

  1. What's the real benefit of the second version with subclasses?

As the article notes, it may be less complex to not have to interrogate one's one state, and this is well illustrated in the male versus female example. However, this does not automatically "[reduce] the complexity" of the code. A smaller conceptual surface area can make a significant difference in the complexity of a code base. So, just because something is using inheritance or some other object oriented design technique, it doesn't necessarily mean it's beneficial.

  1. Should we always consider the second version for such cases?

Plain and simple, 'no'. You can't speak in absolutes, ever (*queue drums for irony). When your hello world program is suffering from interface-itis in order to keep it strictly object oriented, that doesn't necessarily mean it's a good design. Some situations lend themselves to the object oriented structures and some don't; it really needs to be determined on a case by case basis.

Upvotes: 2

Paul92
Paul92

Reputation: 9062

I think this is a bit opinion based.

The basic idea is that in the "enum" (or string constant, or whatever) case, you don't have the flexibility that oop allows you, but just a means of identification by a property of an object and not by its type. Having Men/Woman classes instead of sex as a member of class Person is a good practice since it allows you to further extend your code (i.e. if you want to keep track of beard length for men - this attribute is pointless for women).

However, having an object for everything might be as bad as the other approach. In your specific case, I think you do a bit of over-engineering. I do suggest to follow an iterative approach, and I shall illustrate it using the person example.

Initially, implement a class Person that has an attribute sex (an enum type is just fine). If you start to see separation (in terms of properties or methods) between different type, you can perform the required separation between types.

In your specific case, I think having different classes for different units is a bit impractical (hard to extend in the sense that you need to have a class for every unit - think about things like picometer, femtometer and so on) and unnecessary. However, a better approach would be to store the length internally in some standard unit (i.e. meters) and make the transformation in constructor/setter/getter to whatever unit is required.

Upvotes: 1

Related Questions