Java8: I want to create an interface as follows:
public interface Ui {
abstract static void homeScreen();
abstract static void exitSplash();
}
But I get errors:
error: illegal combination of modifiers: abstract and static
abstract static void homeScreen();
And for static void abstract:
error: <identifier> expected
static void abstract homeScreen();
I want to be able to create a class that has the above methods, where I can write my own method bodies, but have them static, because I don't need to create an object in order to show a home screen or an exit splash (surely I don't - or am I ignorantly trying to force a non OOP approach?).
I don't want to add parameters to the interface methods because imagine two implementations -
What arguments would they have in common? One will be all Swing or equivalent, and the other will be nothing to do with Swing.
There are two questions here:
I think it really boils down to I don't understand the basics. And someone will undoubtedly accuse me of 'not grasping the fundamentals of OOP programming'. But I HAVE read - quite a large chunk of books - but when I try to put things into practice, it requires just that - practice!
Can someone please point me in the right direction with regards to allowed/disallowed combinations of abstract, static etc. for interface method descriptions.
How can I make an interface method for a static class method with no arguments. Its not possible is it!? So how do I solve my little problem of wanting an interface for UI, that can best cover Terminal AND 2D UIs? Give-up and just instantiate the class> Why should I?
NOTE: Here is the (test) class I would like to build an interface to cover. I like it the way it is, with static methods:
import java.io.IOException;
import jline.console.ConsoleReader;
class TestGameScreen2 implements Ui {
private static ConsoleReader con;
public static void homeScreen() {
try {
con.setPrompt("AwesomePrompt> ");
Screen.clear();
System.out.println("Press any key to continue...");
con.readCharacter();
Screen.clear();
System.out.println("Here is a prompt. Do something and press enter to continue...");
String line = con.readLine();
Screen.clear();
System.out.println("You typed: ");
System.out.println(line);
System.out.println("Press any key to exit. ");
con.readCharacter();
Screen.clear();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void exitSplash() {
System.out.println("Thank You. Goodbye.");
System.out.println("");
}
public static void main (String argv[]) {
try {
con = new ConsoleReader();
homeScreen();
exitSplash();
} catch (IOException e) {
e.printStackTrace();
}
}
The reason why you cannot define a method as both static and abstract:
abstractmethods require implementation (via inheritance).staticmembers belong to the class, removing intentions of inheriting. You cannot override astaticmethod, only hide it.
You are most definitely forcing the "non-OOP" approach. There is no reason you should need static for this.
Short-lived objects are very common in object oriented code. Heap is structured specifically to handle objects with different lifetimes. A splash/welcome screen would be a great example of such, only existing for a short period of time.
As for your design, I see you're worried about applying proper OOP design principles. Here's a few flaws I was able to point out:
Single Responsibility: Shoving the code for starting and ending your splash into the UI type makes UI responsible for the splash. You should keep the responsibilities low by allowing a SplashScreen type to handle such. You could then have the UI request a SplashScreen:
abstract class UI {
private SplashScreen splash;
public UI(SplashScreen splash) {
this.splash = splash;
}
public void start() {
splash.start();
init();
splash.end();
}
public abstract void init();
}
The init works as a template method, allowing implementations to initialize themselves during the splash. By moving the code for the splashscreen into another object, we lower the responsibility of the UI. On top of this, you can easily switch splash screens without modifying the class by passing in a different SplashScreen implementation (abiding by the open/close principle).
Interface Segregation: Not all UIs have splash screens. This means some implementations may not make use of startSplash and exitSplash. Instead, you should segregate the interface. Create different abstractions: one which supports splash and one that doesn't:
abstract class UI {
public abstract void start();
}
abstract class SplashableUI {
private SplashScreen splash;
public SpashableUI(SplashScreen splash) {
this.splash = splash;
}
public final void start() {
splash.start();
init();
splash.end();
}
public abstract void init();
}
Interfaces are nice, but they can only abstract behavior, not state. Design with scalability in mind. You may want to add some shared state to your UI type. That would force you to reconstruct all it's implementations in order to convert it to abstract class.
Personally, I use interfaces to bridge the gap between different type hierarchies via behavior. For example:
Entity
/ \
Humanoid Animal
| / \
Human Bird Fish
Human and Fish branch off into 2 different type hierarchies. But they can both swim(). If we wanted a SwimmingPool class which accepts anything that could swim, we have 3 options:
SwimmingPool class (accept(Person), accept(Fish), ect...). But that's not scalableSwimmableEntity type. But then we would need NonSwimmableEntity. On top of that, we would need SwimmableAnimal and NonSwimmableAnimal... You'd have a bunch of very similar interfaces, creating more type hierarchies than needed.Fish and Human implement a Swimmable interface, then allow SwimmingPool to accept objects of that type.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With