0

I develop a Java library which shall run on two different platforms. To print messages, one platform uses printA(str) method, while another uses printB(str) method. In C++, I'd create a static method:

public static void print(string str)
{
    #ifdef platformA
        printA(str);
    #else
        printB(str);
    #endif
}

Since Java has no #ifdef, it becomes a tricky task. I started to look at overriding abstract class with a static method, but not sure I go the right direction. What is the most elegant way to do that?


Edit: With answer of Andy Thomas (thanks!) I found the solution that suits me. The only drawback - it must be initialized on startup. Below is the code. Common library:

//interface is only for internal use in Output class
public interface IPrintApi
{
    public void Print(String message);
}

public abstract class Output
{
    private static IPrintApi m_api;
    public static void SetPrintAPI(IPrintApi api)
    {
        m_api=api;  
    }

    public static void MyPrint(String message)
    {
        m_api.Print(message);
    }
}

Calling of this function is the same in common library and platform-specific code:

public class CommonTest 
{
    public CommonTest()
    {
        Output.MyPrint("print from library");
    }
}

Code for each platform has to have the platform specific implementation of the interface, e.g. platformA (for B it is identical):

public class OutputA implements IPrintApi
{
    public void Print(String message)
    {
        //here is our platform-specific call
        PrintA(message);
    }
}

Usage:

public class AppPlatformA
{
        public static void main(String[] args)
        {
            // point the abstract Output.Print function to the available implementation
            OutputA myPrintImpl = new OutputA();
            Output.SetPrintAPI(myPrintImpl);
            // and now you can use it!
            Output.MyPrint("hello world!");
        }
}
Igor_K
  • 25
  • 6
  • [http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java][1] I think this can help you. – nikoliazekter Oct 30 '14 at 16:16
  • it is not a question of runtime detection, it is more a code design to avoid compile-time issue: printA is not defined when i use the library in platformB, and vice versa... – Igor_K Oct 30 '14 at 17:19

3 Answers3

1

Use a constant expression:

private static final boolean PLATFORM_A = true;

 public static void print(string str)
  {
    if(PLATFORM_A )
    {
       printA(str);
    }
    else
    {
      printB(str);
    }
  }
Sagar Pudi
  • 4,634
  • 3
  • 32
  • 51
  • Constant usage is not really nice. I use it in a library used at the same time on two platforms, namely Windows and Android. And I don't want to change const in common code each time... – Igor_K Oct 30 '14 at 16:53
  • then you can go for System.getEnv() and perform based on the environment. – Sagar Pudi Oct 30 '14 at 16:58
1

What about this code?

    public class Example {

    public static void main(String[] args) {
        print();
    }

    public static void print() {
        String platform = System.getProperty("os.name");
        switch (platform) {
        case "Windows 7":
            System.out.println("This is Windows 7");
            break;
        case "Windows XP":
            System.out.println("This is Windows XP");
            break;
        }
    }
}
Sagar Pudi
  • 4,634
  • 3
  • 32
  • 51
nikoliazekter
  • 757
  • 2
  • 6
  • 23
  • thanks, but the question was more about the different API calls, and not how to detect the platform. – Igor_K Oct 30 '14 at 17:00
0

You could use the strategy pattern.

Define the interface once, and implement it in OS-specific classes.

    public interface IPlatformAPI {
        public void print( String str );
    }

    public class WindowsPlatformAPI implements IPlatformAPI {
        public void print( String str ) { ... }
    }

    public class MacPlatformAPI implements IPlatformAPI {
        public void print( String str ) { ... }
    }

    public class LinuxPlatformAPI implements IPlatformAPI {
        public void print( String str ) { ... }
    }

    public class PlatformAPI {
       public static IPlatformAPI getPlatformAPI() {
          // return one of the platform APIs
          // You can use System.getProperty("os.name") to choose the implementation
       }
    }
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • 1
    Thanks. That sounds interesting. The only unclear point is how to refer in the PlatformAPI class three incompatible classes which cant be compiled together due to different plantform-dependent includes. And the print method in this case can't be defiled as static... – Igor_K Oct 30 '14 at 17:14
  • First, verify that you can't compile all the Java code that targets particular platforms. If you can't, one option is to load the appropriate class at runtime with `Class.forName()` and `Class.newInstance()`. By the way, welcome to StackOverflow. You can *accept* the answer you consider the best by clicking the checkmark to its left. You can *upvote* multiple answers you consider useful. – Andy Thomas Oct 30 '14 at 18:32
  • I accept this as an answer. I had to modify a bit your example, but now it works as I wanted and looks good for me. I will post a sample code a bit later. – Igor_K Oct 31 '14 at 09:45