0
\$\begingroup\$

This program attempts to shows the basic concepts of inheritance and polymorphism. In what ways could the code be modified to better demonstrate those concepts? The interface, abstract class and the class are all in separate files.

Greeting Interface

interface Greeting {
    void sayHello(String greeting, String name);
}

Abstract Hello Class

abstract class Hello {
    String name;
    String greeting;
    public abstract void setName(String name);
    public abstract void setGreeting(String greeting);
    public abstract String getName();
    public abstract String getGreeting();
}

Class that says "Hello"

public class Test extends Hello implements Greeting {
    private String name;
    private String greeting;

    public void setName(String name) {
    this.name = name;
    }
    public void setGreeting(String greeting) {
    this.greeting = greeting;
    }
    public String getName() {
    return name;
    }
    public String getGreeting() {
    return greeting;
    }
    public void sayHello(String g, String n) {
    System.out.print(g + " " + n);
    }
    public static void main(String[] args) {
    Test t = new Test();
    t.setGreeting("Hello");
    t.setName("World!");
    String h = t.getGreeting();
    String w = t.getName();
    t.sayHello(h,w);

    }
}
\$\endgroup\$
  • 4
    \$\begingroup\$ It's hard to say how to improve the code, when it is complicated for the sake of being complicated. What aspirations do you have? Multilingual greeters? Something that can say goodbye? \$\endgroup\$ – 200_success Oct 29 '16 at 20:39
  • \$\begingroup\$ I don't have any aspirations to actually use this code for anything other than maybe an example in a blog post about Inheritance and Polymorphism. The code is purposely complicated to demonstrate those concepts. I am looking for ideas to make the code prettier or more elegant. \$\endgroup\$ – Jim Ferguson Oct 29 '16 at 20:55
  • 1
    \$\begingroup\$ I don't think this shows a good example of polymorphism, considering the interface is effectively unused: nothing is taking or returning a Greeting. \$\endgroup\$ – Tunaki Oct 29 '16 at 21:20
  • \$\begingroup\$ The interface is used. The class Test implements the Greeting interface and overrides the sayHello() method. If it didn't, the code for class Test would not compile. If you're saying that Greeting is a bad name for the interface, I think I see your point. \$\endgroup\$ – Jim Ferguson Oct 29 '16 at 21:53
  • \$\begingroup\$ No, not that it's a bad name. When I'm saying "unused", I'm saying that the interface is not used as method parameter, not used as a return-type, not programed to. Even Test t = new Test(); doesn't use it and could be Greeting t = new Test(). \$\endgroup\$ – Tunaki Oct 29 '16 at 22:00
2
\$\begingroup\$

Your example implementation is not good enough. It's not very complicated at all, as you suggest with the title; rather, it is really simple.

The Hello abstract class is not needed. There is no reason why a class (like a WelcomeEmailContentBuilder or something of the sort) should want to extend Hello - something like a WelcomeEmailContentBuilder might already be extending a ContentBuilder or a EmailContentBuilder. You are abusing the is-a relationship.

Consider this rewrite of your code:

interface Greeting {
    void sayHello(String greeting, String name);
}


public class Test implements Greeting {

    public void sayHello(String greeting, String name) {
        System.out.print(greeting + " " + name);
    }

    public static void main(String[] args) {
        Greeting g = new Test();
        g.sayHello("Hello", "World!");
    }

}

This code is just as functional as your original code. But it's both way shorter and doesn't muck about with an abstract class that you don't need. It also makes use of the Greeting interface for a variable - showing off that you can call functions on objects if you only have an interface.

As for making your code actually show off the use of inheritance and polymorphism, that's up to you to figure out.

\$\endgroup\$
  • \$\begingroup\$ I was trying to demonstrate inheritance using the abstract class and polymorphism using the interface. It seems your example demonstrates both using only the interface. \$\endgroup\$ – Jim Ferguson Oct 29 '16 at 23:04
  • \$\begingroup\$ @JimFerguson Inheritance needs abstract classes or default methods (you inherit implementations). Try using Comparable (java.lang.Comparable) to demonstrate polymorphism, and use abstract classes to compare, say, apples and oranges (both inheriting the compareTo method from their Fruit base class \$\endgroup\$ – Pimgd Oct 29 '16 at 23:17
  • \$\begingroup\$ That idea would be a good demonstration of the concepts. But I wanted the end result of the program to be "Hello Word!" to standard output. "Hello World!" output could be used to illustrate almost all the basic concepts and constructs of Java. For example, there are at least 8 ways to demonstrate scope with the end result being "Hello World!". Thank you for your suggestions. \$\endgroup\$ – Jim Ferguson Oct 29 '16 at 23:28
  • 1
    \$\begingroup\$ @JimFerguson I strongly suggest you don't try to force "Hello world" as result. \$\endgroup\$ – Pimgd Oct 29 '16 at 23:38
0
\$\begingroup\$

As @Pimgd noted, your Hello class doesn't contribute anything. If you remove it, everything works.

Another problem is that it's unclear why you would name the primary method of a Greeting to be sayHello. This is particularly confusing since you have a class named Hello. Why not just say?

Why are you instantiating an abstract Hello as Test? The name Hello seems overly concrete for that. And Test doesn't indicate an extension of Hello to me.

Consider something like

public interface Statement {
    public void say(String name);
}

public abstract class Greeting implements Statement {

    protected final String greeting;

    protected Greeting(String greeting) {
        this.greeting = greeting;
    }

    public String getGreeting() {
        return greeting;
    }

    public void say(String name) {
        System.out.format(greeting, name);
    }

}

public class Hello extends Greeting implements Statement {

    public Hello() {
        super("Hello, %s.");
    }

}

public class Test {

    public static void main(String[] args) {
         Statement hello = new Hello();
         hello.say("World");
    }

}

Now each of the classes does something. If you want to make this clearer, you could add additional greetings or other implementations of Statement.

I also think that this taxonomy fits better. It doesn't entirely convince me, but then this is a toy problem that could be solved with a one liner. I do think that this better fits the constraints (must say "Hello, World." and must have an interface and abstract class).

There is probably a better name for Statement that would include the concept of a name parameter. English.SE or ELL.SE might be better suited to help with that.

By making name a parameter of say, we no longer make a Greeting only work for one person. We also avoid breaking thread safety, although this example won't exhibit that.

I find it rather bizarre that you call getters on an object in order to call a method related to the object. That's exactly why we have objects, so as to encapsulate that kind of logic. So I prefer this version, that doesn't require that kind of behavior.

I'd avoid trying to jam a demonstration of setters into this as well. They don't really fit this model. There's nothing to set in "Hello, World" except the name, and that really seems too localized.

\$\endgroup\$
  • \$\begingroup\$ The point of the exercise is to illustrate. I agree the names are a little "wonky." But, the setters and getters are used to show that the first concrete subclass of an abstract class must implement all abstract methods. \$\endgroup\$ – Jim Ferguson Oct 30 '16 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.