Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intuition vs Design principles

I have a class hierarchy like this Beverage -> Coffee-> Latte. Where Beverage is the abstract superclass being extended by Coffee. Coffee class then adds some behavior but is also abstract. Latte extends Coffee class and is a concrete class. I have used inheritance to add behaviors here. And inheritance do have drawbacks like the visibility of superclass methods, making code fragile, the code is tightly coupled. So, programming principles dictate Composition should be preferred over Inheritance. But in this case inheritance feels so natural as Latte is a type of Coffee and Coffee is a type of Beverage that using composition to add behavior feels wrong in spite of its benefits. So the question here is Should Intuition override Design principles?

Beverage:

public abstract class Beverage {

    private final String name;
    private final double price;

    Beverage(String name, double price){
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }

    public abstract void make();
    }

Coffee:

public abstract class Coffee extends Beverage {

    public Coffee(String name, double price) {
        super(name, price);
    }


    public final void make(){
        grindBeans();
        takeShot();
        frothMilk();
        addCondiments();
    }

    public void grindBeans(){
        System.out.println("Grinding Beans...");
    }

    public void takeShot(){
        System.out.println("Taking Shot....");
    }

    public abstract void frothMilk();
    public abstract void addCondiments();


}

Latte:

public class Latte extends Coffee {

    public Latte() {
        super("Latte", 4.0);
    }

    @Override
    public void frothMilk() {
        System.out.println("Frothing milk to create micro foam");

    }

    @Override
    public void addCondiments() {
        // TODO Auto-generated method stub

    }

}

EDIT: Adding Sugar to existing structure. Only new code is shown.

public abstract class Beverage {

private Sugar sugar;

public Sugar getSugar() {
    return sugar;
}

public void setSugar(Sugar sugar) {
    this.sugar = sugar;
}

}

Coffee:

public abstract class Coffee extends Beverage {

public final void make(){
    grindBeans();
    takeShot();
    frothMilk();
    addSugar();
    addCondiments();
}

public void addSugar(){
    Sugar sugar = super.getSugar();
    if(!(sugar instanceof NoSugar)){
        System.out.println("adding " + sugar.getTeaspoon() + " teaspoon sugar");
    }
}
like image 822
Meena Chaudhary Avatar asked Sep 20 '15 09:09

Meena Chaudhary


People also ask

What is intuition in design thinking?

In product management, intuitive design refers to making products easy to use. With an intuitively designed product, customers will understand how to use it without much effort. They are also less likely to need a tutorial, onboarding, or other help.

What is intuitive design architecture?

The designer often explains the process as intuitive or derived from a natural, unintentional sequence. The intention of this design thesis is to explicitly research intuition, understand intuition's role in creativity, and critically apply these findings to an architectural design process.

What is simple and intuitive design?

Definition. Simple and Intuitive design advocates that the use of the design should be easy to understand, regardless of the users' experience, knowledge, language skills, or concentration level.

What is an example of simple and intuitive use?

Simple and intuitive use. Use of the design is easy to understand, regardless of the user's experience, knowledge, language skills, or current concentration level. Example: Control buttons on science equipment are labeled with text and symbols that are simple and intuitive to understand.


3 Answers

While composition has many benefits over inheritance, there's nothing wrong with using inheritance where it feels natural (i.e. in a truly is-a relationship). If it's natural, go ahead and use it.

like image 93
leeor Avatar answered Oct 22 '22 11:10

leeor


Composition means A has a B, and inheritance means A is kind of B. In your case you're 100% right - inheritance should be used: latee is a cofee and a cofee is a beverage.

Why do you consider it to be fragile? E.g., latee should have all the properties of cofee, but can implement them differently. Nothing fragile here - it's a polymorphism. If you want to restrict overriding of parent's methods - mark them final.

As an example of composition - there are Car and Wheel. Car has a wheel. Car needs wheels for working, but they're completely different objects. Car can be opened, closed, started, etc.. - wheel can't. Wheel can revolute and deflate. Car - can't.

P.S.: Oh, I think I got what you mean by "fragile". Here is an article on it http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should-you-choose-.html For me this "composition instead of inheritance" thing still looks like an OOP hack (especially, the example in the article: apple IS A fruit, no way around it :)) Whenever I will see this hack in use, I would probably think of an API designer to be improvident.

like image 22
smyatkin_max Avatar answered Oct 22 '22 13:10

smyatkin_max


I think in the book head first design patterns the example they use is that the latte class can have several configurations. By using composition you can create custom classes at runtime rather than during design

You can only extend from one class as well which may be a limiting factor depending on what you are doing.

like image 1
pwilcox83 Avatar answered Oct 22 '22 11:10

pwilcox83