Skip to main content

Java Keywords (Part XXIV): native

Java keyword list abstract continue for new switch assert default goto * package synchronized boolean do if private this break double implements protected throw byte else import public throws case enum instanceof return transient catch extends int short try char final interface static void class finally long strictfp volatile const * float native super while Keyword marked with an asterisk (*) are keywords that, although valid, are not used by programmers. This is the last chapter of the Java Keyword series. This is probably the keyword I have used the least. In my 20 year career as a software developer, I have used this keyword once, and that was to make some addition to legacy code. The keyword native is a method modifier . Basically, it is a keyword that can only be applied to methods. According to the Java Language Specification (JLS), A method that is native is implemented i...

Combining State and Singleton Patterns to Create a State-Machine

In my previous two posts, I discussed real-world applications for the Singleton and State design patterns. In this article, I am going to illustrate how to combine both of these patterns to create a simple wizard.

Simple State Design Pattern Implementation

In a typical implementation of the design pattern, State is either an interface or abstract class, with each state of the state machine being Singleton classes. My example is going to be slightly different. I will implement the state machine using a state interface and Java enums to implement the Singleton. Using an enum is the recommended way to implement a Singleton in Java.

First, let's come up with a simple state interface

State.java


public interface State
{
  void goNext(Context input);
  void goPrevious(Context input);
}
Now that we have an interface defined, we can derive as many states as we need. For this example, three states should be sufficient to demonstrate the wizard's functionality. Java allows enum to extend interfaces. Therefore, we can use them just like a regular class.

FirstState.java


public enum FirstState implements State
{
  INSTANCE;
 
  private FirstState () { }

  @Override
  public void goNext(Context context)
  {
    context.setState(SecondState.INSTANCE);
  }

  @Override
  public void goPrevious(Context context)
  {
    // DO NOTHING (No previous state to go to)
  }
}

SecondState.java


public enum SecondState implements State
{
  INSTANCE;
 
  private SecondState () { }

  @Override
  public void goNext(Context context)
  {
    context.setState(ThirdState.INSTANCE);
  }

  @Override
  public void goPrevious(Context context)
  {
    input.setState(FirstState.INSTANCE);
  }
}

ThirdState.java


public enum ThirdState implements State
{
  INSTANCE;
 
  private ThirdState () { }

  @Override
  public void goNext(Context context)
  {
    // DO NOTING (This is the last state)
  }

  @Override
  public void goPrevious(Context context)
  {
    input.setState(SecondState.INSTANCE);
  }
}
As previously stated, because we want our concrete states to be Singletons, we use enum instead of a regular class to ensure any given state is only instantiated once. In other words, we only need a single instance of the first state, a single instance of the second state, and a single instance of the third state. No matter how many times we transition to a state, if an instance of that state already exists, it will use it.

Now, we need to implement the context class.

Context.java


public final class Context
{
  private State current;
 
  public Context ()
  {
    current = FirstState.INSTANCE;
  }

  public void next()
  {
    current.goNext(this);
  }

  public void previous()
  {
    current.goPrevious(this);
  }

  public void setState(State current)
  {
    this.current = current;
  }

  public State getCurrentState()
  {
    return current;
  }
}

In essence, I have created a state-machine with three states.


What's happening so far?

As far as the context object is concerned, there is only a single State that changes states when the correct stimulus (trigger) is applied. In the state-machine diagram above, you can see the "trigger" for one state to go to the next state is labeled "next." This label is exactly the name of one of the methods in the Context class. This is because the context object is the state-machine's controller. When the context receives an instruction to go to the next state (i.e. from a navigation button), it instructs the current State to go to the next state. The context doesn't know what that next state is. Only the State instance knows what that next State is based on what the current state is. In the provided example, the third state doesn't have a valid "next" state. Therefore, when the context tells this state to change to the next, it doesn't do anything and the context keeps ThirdState as the current state. The other two states will change to the next state and will update the context with the next state.

Enhancement to the State Interface

It might be nice if we had a way to ask a state if it has a previous or next state. After all, a state-machine with a single state is pretty much worthless. You could say that a State most likely has a previous state and a next state. For example, the ThirdState enum knows it doesn't have a valid "next" state. The problem is that adding such methods will require a change in the State interface, which in turn will break every state enum created. Well, I have good news and bad news. The bad news is that this change will require a change in the interface. The good news is that it will not break the current state enum implementations. At least, not entirely.

Java 8 introduced the concept of Default Methods. Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces. I want to enhance the State interface by adding a method to find out if the state has a current state and another to find out if the state has a next state. In addition to these two methods, I will add a default method to give a State object the ability to return its identity by returning it's class name. This method will come very handy when integrating this state-machine with a Java Swing interface.

State.java


public interface State
{
  ...
  default boolean hasNext() { return true; }
  default boolean hasPrevious() { return true; }
  default String getName()
  {
    return this.getClass().getSimpleName();
  }
}

You specify that a method definition in an interface is a default method with the default keyword at the beginning of the method signature. With this interface, you do not have to modify any of the State enums. However, both these default methods return true and this not the case with the first and third states. While the first state has a next state, it doesn't have a previous. The opposite is true of the third state. So, what do we do now? All we need to do is to override the appropriate method in whichever class needs it. For example, the FirstState needs to override the hasPrevious() method, and the ThirdState needs to override the hasNext() method. The SecondState can remain unmodified.

FirstState.java


public enum FirstState implements State
{
  ...
  @Override
  public boolean hasPrevious() { return false; }
}

ThirdState.java


public enum ThirdState implements State
{
  ...
  @Override
  public boolean hasNext() { return false; }
}

Read next: Simple Wizard controlled by this state-machine using Swing for the GUI.

Comments

Popular posts from this blog

Implementing Interfaces with Java Records

If you have not read my article on Java records and do not know about this topic, please read my blog titled " Customizing Java Records " first and then come back to this one. Now that you know how to customize Java records, implementing an interface using Java records should be very easy to understand. If you don't know about interfaces in Java, you can read more on my article about interfaces. The recipe for implementing an interface is simply an expansion of what you learned in my previous blog on how to customize a Java record. Following our Rectangle example, let's create an interface with the same two methods we used before. public interface Shape { double area(); double perimeter(); } Now, let's further customize the previous example by doing two things: Add implements Shape at the end of the record declaration (after the record constructor), and Add @Override to the existing methods to ensure these methods com...

Customizing Java Records

If you have not read my article on Java records and do not know about this topic, please read my blog titled " Java Keywords Addendum: The Java Record " first and then come back to this one. What is a customization of a record? A customization of a record is simply the addition of code inside the body of the class. Before proceeding further, let's recap important aspects of a Java Record: Java records are immutable Because of item 1 above, you cannot add new fields unless defined in the record constructor Java records already override: Object#equals(Object) and Object#hashCode() , and then override Object#toString() You could redefine overridden methods as part of your customization if you would like. For example, if you want a fancier implementation of the Object#toString() method, you could do so. Let's look at our first customization example. Using the example from my previous blog, public record Student(...

Object-Oriented Programming Basics: What is in a Class?

EDITORIAL NOTE : This article was published briefly back in 2016 and quickly set back to draft because I wasn't happy with its contents. It is a shame that it was taking me three years to revisit this topic and work on a new and improved version. At least, I'm hoping it will be to the liking you the reader. Keep in mind that the opening paragraph will still read as if I just wrote it for my (former) students at Texas Wesleyan. I started working on lecture on the topic of Object-Oriented (OO) Programming by gathering some material, old and new, when I realized this might be good and simple post for my second attempt at blogging. To be completely honest, in the 8 hours I spent collecting information and preparing material for this week's lecture, I realized I still made some of the mistakes I am about to blog about. I am actually hoping I can write a series of postings regarding Object-Oriented Programming (OOP). But to do so, I must start from the very beginning. ...