How to achieve abstract variable functionality in Java - java

I am trying to create a custom class that extends another class (JFrame) but forces the assignment of a certain variable upon implementation (I want each JFrame in my application to have a "screen ID"). Java, however, does not have abstract variables. Nor am I able to figure out how to make an interface that extends JFrame. This one's really got my head spinning =D
The class code would look similar to this:
public interface CustomFrame extends javax.swing.JFrame {
public abstract int screen_id;
}
And the implementation of CustomFrame would look something like this:
public class NewFrame implements CustomFrame {
public int screen_id = 5;
NewFrame() {
setVisible(true);
// etc...
}
}
Does this problem even make sense to anyone?? I know what my objective is I am just lost trying to work it out in my brain....

Create an external FrameID generator that generate a new ID at each call (just a simple example implemented as singleton: no synch or generic return type etc):
class FrameIDGenerator {
private static int nextID = 0;
private FrameIDGenerator(){}
private static FrameIDGenerator instance = null;
public final static FrameIDGenerator getInstance() {
if(null == instance) instance = new FrameIDGenerator();
return instance;
}
public int getNextID() {
return ++nextID;
}
}

From what I am understanding, it is a 3rd party (not JFrame itself) who needs the number. I don't think it's a good idea to try to force JFrame (who already has a lot of concerns) into this burden.
Please consider the alternative of keeping an external IdentityHashMap<JFrame,Integer> to store this information.

Related

Java: Inner classes accessing each other's private variables - good practice for encapsulating external API?

This is a bit of a design question involving inner classes in Java (Java 8). All of the example code is below my text
As an example, let's say I have some machinery that involves pumping fuel from an oil geyser to some sort of burner, which I can control using an external API called OilAPI.
I have a Controller class which is doing the work and decides which burner needs to get oil from which geyser, but I don't want the logic of using the API's classes like Geyser and Burner to leak out into the Controller (also since the API does still undergo some changes over time).
Now, to encapsulate it, so I create a class called FuelFacility which contains all of the logic of the OilAPI.
The thing is, I've put the classes Pump and Engine as inner classes inside of FuelFacility.
First of all, this is for the syntax of being able to go Pump.activate() instead of FuelFacility.activatePump(...) or whatever.
Further is that in order to connect a Geyser and Burner in the Oil API, you need both the Geyser and Burner objects, but I don't want to expose them externally, so in order to have some sort of "Connect Pump and Engine" method, I have to allow either the Pump to access the Engine's Burner variable, the Engine to access the Pump's Geyser +variable, or the FuelFacility to access both these variables. In the example below, I have a Engine.connectToPump(pump) method, which is basically the way it works in my actual code.
My teammates thought that this is a bit strange; they said that the accessing the private variables across the classes breaks encapsulation, and especially that a programmer looking at the code from the "outside" (i.e., from the point of view of working in the Controller class) would assume that once you have obtained the Engine and Pump objects, they would no longer depend on e.g. which OilAPI object the original FuelFacility is using (although this should remain final, as I've done below) nor on each other.
Now, since then, I've managed to change their minds a bit - that basically this is just a way of doing things that they're not used to, but that it's not bad practice.
However, now I am busy altering some other code to work in a similar fashion to this, and I just want to make sure before I continue, is what I am doing good practice? Is there a better way of doing things? Advice is appreciated!
CODE:
Oil API (not under my control):
public class OilAPI {
private final Pipes pipes = new Pipes();
public static class Geyser {}
public static class Burner {}
public static class Pipes {
public void createConnectionBetweenGeyserAndBurner(Geyser g, Burner b) {
// Connects geyser and burner
}
}
public Geyser getGeyserWithId(String id) {
// Actually retrieves a specific instance
return new Geyser();
}
public Burner getBurnerWithId(String id) {
// Actually retrieves a specific instance
return new Burner();
}
public void activateGeyser(Geyser g) {
// do stuff
}
public void activateBurner(Burner b) {
// do stuff
}
public void createConnectionBetweenGeyserAndBurner(Geyser g, Burner b) {
pipes.createConnectionBetweenGeyserAndBurner(g,b);
}
}
Fuel Facility (class I created to encapsulate the Oil API):
public class FuelFacility {
private final OilAPI oil;
FuelFacility(OilAPI oil) {
this.oil = oil;
}
public Pump getPumpForId(String id) {
OilAPI.Geyser geyser = oil.getGeyserWithId(id);
return new Pump(geyser);
}
public Engine getEngineForId(String id) {
OilAPI.Burner burner = oil.getBurnerWithId(id);
return new Engine(burner);
}
public class Pump {
private final OilAPI.Geyser geyser;
private Pump(OilAPI.Geyser geyser) {
this.geyser = geyser;
}
public void activate() {
oil.activateGeyser(geyser);
}
}
public class Engine {
private final OilAPI.Burner burner;
private Engine(OilAPI.Burner burner) {
this.burner = burner;
}
public void connectToPump(Pump pump) {
oil.createConnectionBetweenGeyserAndBurner(pump.geyser, burner);
}
public void activate() {
oil.activateBurner(burner);
}
}
}
Controller (owned by me, and sits inside of our codebase):
public class Controller {
public static void main(String[] args) {
// We actually get these from a database
String engineId = "engineId";
String pumpId = "pumpId";
OilAPI oil = new OilAPI();
FuelFacility facility = new FuelFacility(oil);
FuelFacility.Engine engine = facility.getEngineForId(engineId);
FuelFacility.Pump pump = facility.getPumpForId(pumpId);
engine.connectToPump(pump);
}
}
Having inner classes access each others' private fields isn't necessary bad in itself. It seems that your main goal is to protect Controller from changes to OilAPI. In this design, FuelFacility, Pump, and Engine are so close to OilAPI, Geyser, and Burner that I'm not sure you actually protect Controller all that much. FuelFacility should be designed more for what Controller needs than what OilAPI does. In your example, you don't call activate on the Pump or Engine but I'm assuming you'd ultimately want to do that. First, I'd start by declaring some interfaces:
public interface PumpEngineConnection {
public void activate();
}
public interface FuelFacility {
public PumpEngineConnection connect(String pumpId, String engineId);
}
Controller works through these interfaces and does not know what implementations that it actually uses. Then you can make a OilAPIFuelFacility implementation of FuelFacility. The PumpEngineConnection implementation that it returns will be one specifically designed to work with OilAPIFuelFacility. You could do this with an inner class:
public class OilAPIFuelFacility implements FuelFacility {
private final OilAPI oil;
public OilAPIFuelFacility(OilAPI oil){ this.oil = oil; }
#Override
public PumpEngineConnection connect(String pumpId, String engineId){
Geyser geyser = oil.getGeyserWithId(pumpId);
Burner burner = oil.getBurnerWithId(engineId);
oil.createConnectionBetweenGeyserAndBurner(geyser, burner);
return this.new GeyserBurnerConnection(geyser, burner);
}
private class GeyserBurnerConnection implements PumpEngineConnection {
private final Geyser geyser;
private final Burner burner;
private GeyserBurnerConnection(Geyser geyser, Burner burner){
this.geyser = geyser;
this.burner = burner;
}
#Override
public void activate() {
OilAPIFuelFacility.this.oil.activateGeyser(this.geyser);
OilAPIFuelFacility.this.oil.activateBurner(this.burner);
}
}
}
Each GeyserBurnerConnection implicitly gets a reference to the OilAPIFuelFacility that created it. That's reasonable because it only makes sense to use a PumpEngineConnection with the FuelFacility that created it. Likewise, it's perfectly reasonable for GeyserBurnerConnection to reference the oil member from OilAPIFuelFacility.
That said, it may make more sense for GeyserBurnerConnection to be a package-private class in the same package as OilAPIFuelFacility. It may be that different versions of the OilAPI can use the same GeyserBurnerConnection class.
Finally, the Controller could look something like this:
import com.example.fuelfacility.FuelFacility;
import com.example.fuelfacility.PumpEngineConnection;
public Controller {
private final FuelFacility fuelFacility;
public Controller(FuelFacility fuelFacility){
this.fuelFacility = fuelFacility;
}
public void example(){
String pumpId = "pumpId";
String engineId = "engineId";
PumpEngineConnection connection = fuelFacility.connect("pumpId", "engineId");
connection.activate();
}
}
Note that it's completely ignorant of what implementation of FuelFacility and PumpEngineConnection it actually uses. In practice, we'd pass in OilAPIFuelFacility with a dependency injection framework or an external Main class.
I realize that your example is probably simplified from what you actually need to do. Nonetheless, you should really think in terms of what Controller needs and not what OilAPI does.
Finally, I should note that I generally agree with your colleagues' concerns about your design. Consider this snippet:
OilAPI oil1 = new OilAPI();
OilAPI oil2 = new OilAPI();
FuelFacility fuel1 = new FuelFacility(oil1);
FuelFacility fuel2 = new FuelFacility(oil2);
Engine engine = fuel1.getEngineForId("engineId");
Pump pump = fuel2.getPumpForId("pumpId");
engine.connectToPump(pump);
What happens? Then oil1 is used to connect a Pump which was retrieved through oil2. Depending on the internals of OilAPI that would likely be a problem.

how to toggle the right class for checkbox listener?

I have a GUI with a start button and a checkbox that creates multiple instances of Class A (A blueprint of my web service) based on given text input. The checkbox if checked writes some additional elements to the XML file (which is the main output of the entire application). Now I want to add an additional checkbox which will provide the GUI to create instances of Class B which extends Class A but provides some additional fields and logic.
My question is that how can I implement this required functionality?
Given there is a createMyXML() method in class C which is doing the same for hardcoded arguments as Class A or Class B for its methods, should I extend it to take one of the class as a parameter and create instances for required elements in the XML?
P.S. It is probable that this question may be too subjective but I wonder what could be the approach or the 'right way' to do it.
Class A Anatomy
public class A {
private String id;
private Vector<String> inputs;
private Vector<String> outputs;
//***Getters and Setters for above.***
}
Class C Anatomy
public class C {
void createMyXML(){
for (A a : this.parser.getAttributes()){
createFirstElement(A a);
createSecondElement(A a);
// Or (This behavior should be triggered by the checkbox)
createFirstElement(B b);
createSecondElement(B b);}
}
If I understand your question right, you want a way of creating different instances that would create XML files based on some logic that differs from class to class, preferably easily extendable later on.
In this case the Factory Design Pattern seems like a reasonable solution. You define an interface with the craeteMyXML() method:
public interface I {
public void createMyXML();
}
Add a class for each XML creation logic. In this example I've added two classes: A and B, which implement the I interface.
Class A:
import java.util.Vector;
public class A implements I {
private String id;
private Vector<String> inputs;
private Vector<String> outputs;
#Override
public void createMyXML() {
System.out.println("Create XML by the rules of A.");
}
/* Getters and setters and other methods needed*/
}
Class B:
public class B implements I {
#Override
public void createMyXML() {
System.out.println("Create XML by the rules of B.");
}
}
You can use an enum as a parameter for the factory based on which it creates instances. You can use other options as well, for example a String value or int, it depends on your solution. Here, I define the available instances as an enum:
public enum Instance {
A, B
}
The Factory class creates instance of A or B using the super-type I.
public class Factory {
public static I createInstance(Instance i) {
if (i == Instance.A) {
return new A();
} else if (i == Instance.B) {
return new B();
} else {
return null;
}
}
}
I'm adding a Test class to quickly test this solution, you can incorporate it in your project.
public class Test {
public static void main(String[] args) {
I a = Factory.createInstance(Instance.A);
I b = Factory.createInstance(Instance.B);
a.createMyXML();
b.createMyXML();
}
}
When you execute this, it will produce the output:
Create XML by the rules of A.
Create XML by the rules of B.

Should constant details be part of the abstraction or the implementation?

I have a SaveSettings network operation in my application.
I am using an adapter so that I can be free to plug in another networking library in the future and not change any of my code.
public interface SaveSettingsOnServerAdapter {
void saveSettings(User user, OnSaveSettingsOnServerListener listener);
}
public class SaveSettingsOnServerAdapterImpl implements SaveSettingsOnServerAdapter {
private static final String API_USER_SESSION_HEADER = "Cookie";
private static final String API_SAVE_SETTINGS_PATH = "user/{user_id}/update";
private static final String API_SAVE_SETTINGS_USER_ID_PATH_PARAMETER = "user_id";
private static final String API_SAVE_SETTINGS_SYNC_WITH_CALENDAR_PARAMETER = "sync_with_calendar";
private static final String API_SAVE_SETTINGS_USE_MOBILE_NETWORK_PARAMETER = "use_mobile_network";
#Override
void saveSettings(User user, OnSaveSettingsOnServerListener listener) {
// Some implementation here, in my case - RETROFIT
}
}
My gut feeling tells me that those details outlined in the constants defined in the Implementation class are independent of whatever networking library I choose to use for the networking, so they should be part of the abstraction, right?
If so, should I declare SaveSettingsOnNetworkAdapter abstract and insert them there? And then SaveSettingsOnNetworkAdapterImpl extend it instead of implement it? Is it a problem to extend an abstract class instead of implementing an interface when employing the Adapter pattern?
Downgrading an interface to an abstract class isn't unproblematic. You force all future implementations to extend that class and only that class, whereas currently you can attach the interface to almost anything.
Plus, the parameters may be constant (as far as you can tell now) but is it really the responsibility of a SaveSettingsOnServerAdapter to keep & define them?
They are required in there for sure. But requirements can be provided by other places as well. The most versatile / abstract solution to that is to define another interface that provides the values and to add the dependency to that interface to the constructor of every SaveSettingsOnServerAdapter implementation.
If you don't like to repeat that constructor, that would be a good place to make an abstract class that implements SaveSettingsOnServerAdapterImpl and covers the common code to deal with the external interface.
But it's up to you. Whether you want more encapsulation and to which degree you want that depends on what you're working on. In a tiny tool that isn't going to change is pointless since abstractions aim to make change easy. And more abstraction also means more code and more code means more places that can break.
public interface ServerConfiguration {
String getHeader();
String getPath();
...
}
public enum DefaultServerConfiguration implements ServerConfiguration {
INSTANCE;
private static final String API_USER_SESSION_HEADER = "Cookie";
private static final String API_SAVE_SETTINGS_PATH = "user/{user_id}/update";
...
#Override
public String getHeader() {
return API_SAVE_SETTINGS_PATH;
}
#Override
public String getPath() {
return API_SAVE_SETTINGS_PATH;
}
...
}
public class SaveSettingsOnServerAdapterImpl implements SaveSettingsOnServerAdapter {
private final ServerConfiguration config;
public SaveSettingsOnServerAdapterImpl(ServerConfiguration config) {
this.config = config;
}
#Override
void saveSettings(User user, OnSaveSettingsOnServerListener listener) {
new Request().withHeader(config.getHeader());
}
}
public class UserOfAllThis {
new SaveSettingsOnServerAdapterImpl(DefaultServerConfiguration.INSTANCE);
}
The idea of abstraction is to make your code more generic. This should hide implementation as much as possible. Adding constants to the abstract layer will reveal some implementation details. The best way will probably be to add the constants to the implementation class or create a new class with these constants.

Get a variable from a different class

So I'm trying to cut back on some of the code that's been written. I created a separate class to try this. I have that class working correctly, however the old one uses variables that are now in the separate class. How do I access these variables? Unfortunately I can't share all the code for this, but I can give out small pieces that I think are necessary. Thanks for the help
This is from the old class that I am now trying to bring the variable to: I'm trying to bring "loader" over
// XComponentLoader loader = null;
fixture.execute(new OpenOfficeOpener());
component = loader.loadComponentFromURL("file:///"+System.getenv("BONDER_ROOT") + "/ControlledFiles/CommonFiles/"+spreadsheet, "_blank", 0, loadProps);
You can write getters for the members that you need to be visible outside. Example:
public class MyClass {
private int member1;
private String member2;
public int getMember1() {
return member1;
}
public String getMember2() {
return member2;
}
}
Now both member1 and member2 can be accessed from the outside.
There are a couple of solutions to your problem. What I would suggest is to add a method in your class to return the value to the new program, or pass it as a parameter.
An example of this on a higher level might look like this:
x = newClass.getValX()
It sounds like you're looking for a static field, though if is the case you almost certainly reconsider your current design.
public class YourClass {
private static XComponentLoader loader;
public YourClass() {
YourClass.loader = new XComponentLoader();
}
}
And to access it from another class:
public YourOtherClass {
public void yourMethod() {
YourClass.loader ...
}
}
If loader is static, than do something like:
component = TheOtherClass.loader.loadComponentFromURL( ...
Otherwise, your new class needs a reference to an instance of the other class. You could pass it with the constructor:
public class NewClass {
private OldClass oldClass = null;
public NewClass(OldClass oldClass) {
this.oldClass = oldClass;
}
// ...
fixture.execute(new OpenOfficeOpener());
// assuming, loader is a public field on OldClass.
// a getter (getLoader()) is preferred
component = oldClass.loader.loadComponentFromURL("file:///"+System.getenv("BONDER_ROOT") + "/ControlledFiles/CommonFiles/"+spreadsheet, "_blank", 0, loadProps);
// ...
}
I've you've split functionality into two classes, then you may want to have one class instantiate another.
If you've put your new code in Class B then it might look like this.
public class A {
// Class B instance
B b = new B();
public void doSomething() {
b.loadComponentFromURL("someurl");
}
}
Or if the loader is an instance itself, you could call it like this.
b.getLoader().loadComponentFromURL("someurl");

Loading a class based on a level/stage?

I have come across a bit of a problem. I have a class called "GameScreen" which will know what level and stage has been selected. From that I can build a string to suggest something like "level1_1" or "level1_2". The problem is how do I load this class now?
I was going to use Class.forname(string) however each level is a different class so how do I pass the new operator to the class?
I am trying to achieve something like this... world = new World(worldListener); where "World" is the class such as "level1_1".
Hope that makes sense.
Aside from the fact that there are much better ways to implement this (see the other answers, for example), this should work (not tested, ignores exceptions, may cause abdominal distention, etc.):
public World createWorld(String levelClassName, WorldListener listener) throws Exception
{
Class<?> clazz = Class.forName(name);
Constructor<World> ctor = (Constructor<World>) clazz.getConstructor(WorldListener.class);
World world = ctor.newInstance(listener);
return world;
}
You must use reflection (java.lang.reflect)
First, even if the class for each level is different, all of them should extend/implement a common superclass/interface so basic operations are available (v.g. a constructor, a startLevel() method, and so on).
With reflection, you can chose the class related to your level, instantiate it, and pass it to your engine so it invokes your class.
As a side note, I find the architecture strange. Unless there is some other reason to do this, I would suggest using a unique class for levels and loading the configuration for each level from files. It may not be suited if gameplay changes between level, though.
See the Factory Pattern. For your case you could implement a CreateLevel(String level) method which does a simple case-statement to determine which class to create or use reflection.
Um... there's 101 better ways of doing that.
Update For example:
public abstract class Level {
// or whatever your interface is
abstract public void createWorld(WorldListener worldListener);
abstract public void nextWorld();
}
public class Level1 extends Level {
public void createLevel(WorldListener worldListener) {
/** do it **/
}
public Level nextLevel() { return new Level2(); }
}
Then somewhere else:
Level cur = new Level1();
do {
cur.createLevel(worldListener);
...
cur = cur.nextLevel();
} while (cur != null);
Original
For example:
public abstract class Level {
final public int number;
public Level(int num) { this.number = num; levels[num-1] = this;/* set up level */ }
// adjust 10 to number of levels
static private Level[] = new Level[10];
static public getLevel(int num) { return levels[num-1]; }
// or whatever your interface is
abstract public void createWorld(WorldListener worldListener);
}
public class Level1 extends Level {
public Level1() { super(0); }
public void createWorld(WorldListener worldListener) {
/** do it **/
}
}
Then somewhere else:
Level.getLevel(1).createWorld();

Categories

Resources