I instantiate two dependent classes:
//Create and set up the content pane.
ImportTablePanel surveyTablePanel = new ImportTablePanel(genErrorDescArray);
SurveyTree surveyTreePanel = new SurveyTree(surveyTablePanel,genErrorDescArray);
The SurveyTree class has a method setImportOK() that I wish to access from the ImportTablePanel class.
public class SurveyTree extends JPanel
implements TreeSelectionListener {
...
public void setImportOK(){
// my code here
}
The problem I have is that instantiation of a SurveyTree object takes the ImportTablePanel as a parameter. This makes it very difficult to get a reference to the SurveyTree object.
After many attempts, I finally have managed to get this to work by navigating upwards from the table container - see code below.
I am sure there is a much better way to get a container reference - ideally something like table.getContainer(int indexFromTop) can anyone make a suggestion?
public class ImportTablePanel extends JPanel implements TableModelListener {
...
SurveyTree surveyTree = (SurveyTree) table.getParent().getParent().getParent().getParent().getParent().getParent().getParent().getParent();
surveyTree.setImportOK();
}
Many thanks..
In the end I used a singleton design pattern.
public class SwingUtility {
private static SwingUtility instance;
private static SurveyTree surveyTreePanel;
SwingUtility() {
}
public static synchronized SwingUtility getInstance(){
if (instance == null){
instance = new SwingUtility();
}
return instance;
}
public SurveyTree getSurveyTreePanel() {
return surveyTreePanel;
}
public void setSurveyTreePanel(SurveyTree surveyTreePanel) {
SwingUtility.surveyTreePanel = surveyTreePanel;
}
}
create singleton instance with main method
// set up singleton instance of survey form
SwingUtility swingUtility = new SwingUtility();
swingUtility.setSurveyTreePanel(surveyTreePanel);
Then reference the SurveyTree from the Import Table Panel
SurveyTree surveyForm = SwingUtility.getInstance().getSurveyTreePanel();
surveyForm.setImportOK();
Related
I have parent class Hammer and then his child class Mjolnir. I want to set the remainingUsage for Mjolnir to 4. I managed to do it by creating method in Hammer classs called setUsage and then use it in Mjolnir constructor. Is it possible to do it in more easy way without that setUsage method?
public class Hammer extends AbstractActor {
private int remainingUsage;
private Animation image;
public Hammer() {
this.remainingUsage = 1;
image = new Animation("sprites/hammer.png");
setAnimation(image);
}
}
public class Mjolnir extends Hammer {
Mjolnir(){
super();
this.setUsage(4);
}
}
You can do something like this:
...
private remainingUsages;
public Hammer() { this(1); }
public Hammer(int remainingUsages) { this.remainingUsages = remainingUsages; }
And then just call super(4) from your subclass. Calling other methods within your constructor is not good practice.
I don't know if this is possible, and that is why I need your help.
What I want to do is that I want to add objects to a Vector. The problem is that the objects are created in another class.
Is it possible?
Here is my code:
class Factory {
public Factory() {
Action run = new RunAction();
Action climb = new ClimbAction();
}
}
public class Game {
private Vector<Action> actions = new Vector<Action>();
public Game(Factory fact) {
actions.add(XXXX); ****//What to write here to add the actions created in Factory? Somehow I want to use fact for this.**
}
}
class ClimbAction extends Action {
public ClimbAction() {
super("Try to climb\n");
}
}
class RunAction extends Action {
public RunAction() {
super("Try to run\n");
}
}
class TestClass {
Factory f = new Factory();
Game game = new Game(f);
}
Change your factory class to this:
class Factory {
private Action run;
private Action climb
public Factory() {
run = new RunAction();
climb = new ClimbAction();
}
public Action getRunAction(){ return run; }
public Action getClimbAction(){ return climb; }
}
From that, you can access run and climb through a provided instance of the factory class. e.g. factory.run.
Your code defines the two variables run and climb only in the scope of the Factory class' constructor. Therefore, they can only be accessed from there.
EDIT
Also, you seem to want to add all the actions from the Factory to your game. I would therefore advise you add a vector of actions to your factory and add the run and climb actions through the constructor:
class Factory {
private Vector<Action> actions = new Vector<Action>();
public Factory() {
actions.add(new RunAction());
actions.add(new ClimbAction());
}
public Vector getActions(){ return actions; }
public void setActions(Vector v){ actions = v; }
}
public class Game {
private Vector<Action> actions = new Vector<Action>();
public Game(Factory fact) {
//add every action in factory to game actions.
for(Action a : fact.getActions())
actions.add(a);
}
}
I hope this helped!
Your Factory class is not very useful yet: It creates two objects on construction...which can be garbage collected immediately.
Consider a Factory class like this:
final class Factory {
public [static] Action createRun() {
return new RunAction();
}
public [static] Action createClimb() {
return new ClimbAction();
}
}
This class looks a little more "Factory-Pattern-like", and it(static)/an instance can be used to populate your vector.
Create variables in the Factory class, and provide access to them (below demonstrates doing so by defining the variables as private, with access via a getter methods).
class Factory {
private Action run;//Access modifier is private
private Action climb;
public Factory() {
run = new RunAction();
climb = new ClimbAction();
}
public Action getRunAction(){
return run;
}
public Acti8on getClimbAction(){
return climb;
}
}
In the Constructor, use the getter methods of Factory to access the variables:
public Game(Factory fact) {
actions.add(fact.getRunAction()); ****//What to write here to add the actions created in Factory? Somehow I want to use fact for this.**
}
I'm new here so please forgive possible mistakes :)
I'm writing a game as a final project for my coding classes. And...I'm really stuck. I want to create one object of certain class BUT later on I need to pass there different data from different other classes so I can save all data at the end of using a program.
For example I create an object in MainFrame and get a name of a user from there. Then I go to NextFrame and get age of a user etc etc.
I'd appreciate the answers in as simple english as possible, I'm not fluent :)
I'm using netbeans btw.
Thanks a lot !
Simply try the Singleton Design Pattern.
Simple Example for that:
class SingletonClass {
private static SingletonClass instance = null;
private String customAttribute;
public SingletonClass() {
//default constructor stuff here
}
//important singleton function
public static SingletonClass getInstance() {
if(instance == null)
instance = new SingletonClass();
return instance;
}
// getter and setter
}
now, in your frame or any other class you just do the following:
SingletonClass myObject = SingletonClass.getInstance();
when this function is called for the first time, a new Object is created. Later, it returns the first created. With the help of the Singleton Pattern you can easily save data in one object across multiple classes.
for more information about Singleton:
http://en.wikipedia.org/wiki/Singleton_pattern
hope this helps.
just pass the object to the class you want to, and use it accordingly in a method that you want to ! Here is an example with two classes:
class oneClass {
void oneMethod() {
Class1 myClass1 = new Class1();
Class2 myClass2 = Class2 Class2();
myClass2.setMyClass1(myClass1);
}
}
class Class2 {
Class1 myClass1;
//...
void setMyClass1(Class1 myClass1) {
this.myClass1 = myClass1;
}
//...
void doSomething() {
// do something with instance variable myClass1
}
}
In your case Class1 can be MainFrame and Class2 can be NextFrame or however you want to call them...
As you can see from my code, you pass the class myClass1 to myClass2 using the following line of code : myClass2.setMyClass1(myClass1); and then you can work in this object any way you want
Just send the object of your MainFrame class using a method to wherever you want. The object will contains all data from whenever you change it from different method.
If you need a single object MainFrame all over the class then you may consider of using singleton pattern for creating the object.
to save things to a file(or stream) you can use interface serializable:
import java.io.Serializable;
import java.util.ArrayList;
public class Test implements Serializable {
public ArrayList<Object> urDiferentKindOfThings = new ArrayList<Object>();
public boolean add(Object o) {
if (o != null) {
urDiferentKindOfThings.add(o);
return true;
}
return false;
}
}
Now, just add anything (Object!) that you want to save, then at the end of your game just save the object of type TEST that should contain all your stuff (you may need to read about serializable as it make life easy)
Good Look
You pass class instances into a managing class
public class Game {
private MainFrame mainframe = null;
private NextFrame nextframe = null;
public Game(){
this.mainFrame = new MainFrame();
this.nextFrame = new NextFrame();
}
public Game(MainFrame mainFrame, NextFrame nextFrame){
this.mainframe = mainFrame;
this.nextframe = nextFrame;
}
public String getName(){
return mainFrame.getName();
}
public int getAge(){
return nextFrame.getAge();
}
}
public class MainFrame {
private String name = "John"
public String getName(){
return name;
}
}
public class NextFrame{
private int age = 25;
public int getAge(){
return age;
}
}
class a{
function dosomething(){
//code goes here
}
}
class b{
a firstobject=new a();
c secondobject=new c(a objtopass); //passing object of a to c
function donext(){
//next code
}
}
class c{
a receivedobj=null;
public c(a objtoreceive){
//constructor
receivedobj=objtoreceive;
}
function doAdd(){
//function code
}
}
I came cross a class with private constructor but the object is returned by another public method by call to the private constructor. What may be the advantage of such a construct when we could have made the constructor public?
public final class TokenTable {
static public int errorToken = 0;
static public int timesToken = 1;
static public int divToken = 2;
static public int plusToken = 11;
......
......
private final HashMap<String, Integer> keywordMap = new HashMap();
private final HashMap<String, Integer> operationMap = new HashMap();
private TokenTable() {
operationMap.put("*", timesToken);
operationMap.put("/", divToken);
operationMap.put("+", plusToken);
....
}
static public TokenTable getInstance() {
LexTokenTabInstance = new TokenTable();
return LexTokenTabInstance;
}
}
This is called the Factory pattern. Check out the description here - Factory Design Pattern.
There are several advantages:
you can have multiple named factory methods to create different flavors of the object which can allow for overloading with the same set of parameter types
you can return a singleton if appropriate or maybe return one of a cached set of instances
if don't need to use new
when using generics, the generic type is inferred by the compiler so don't need to use the <> operator
you can return an interface instead of a concrete class
allows for pre-constructor initialization (for example if init must be done prior to calling base class constructor)
To be clear, the above example it seems that it was done just as a "good practice" since none of the above capabilities was used (other than you don't have to use "new").
This is called a factory method. A factory method has many advantages over a constructor:
it has a name (and multiple factory methods may have different names)
it allows returning a cached instance instead of a new instance
it allows returning a subclass instance instead of the actual class
etc.
The main advantage is that no one can create an instance, but using static getInstance method.
This way you can make sure only one instance is created, just as Singelton design pattern
The primary reason for hiding a constructor of a class is to control how objects of that class are created. A common example of this is in the Singleton pattern, where only one object of a class is instantiated.
In order to police this, the user accesses a static method which will access the private constructor if the object isn't created, or else return a reference to the already created object:
public class SingletonDemo {
private static volatile SingletonDemo instance = null;
private SingletonDemo() { }
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class){
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
}
For other examples, look at Factory patterns in general: http://en.wikipedia.org/wiki/Factory_method_pattern
If you do not want to protect creation of multiple instance outside the class then you can create private constructor.
This is helpful creating a single instance.
You can do it like(Eager loading):
private static final TokenTable tokenTable = new TokenTable();
static public TokenTable getInstance() {
return tokenTable;
}
Or, you can do it like(Lazy loading):
private static TokenTable tokenTable;
static public TokenTable getInstance() {
if(null == tokenTable){
tokenTable = new TokenTable();
}
return tokenTable;
}
The most common way of implementing a singleton in java is to use a private constructor with a public accessor method of the form --
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
However, since the constructor is private, it prevents subclassing the singleton. Is there any way in which we can make a singleton which allows subclassing ?
When you have a class A extends B, an instance of A essentially "includes" instance of B. So the very concept of inheritance is contrary to the singleton model.
Depending on what you need it for, I would consider using composition / delegation. (A would have a reference to the singleton, rather than extending its class). If you need inheritance for some reason, create an interface with the Singleton methods, have Singleton implement that interface, and then have another class also implement that interface, and delegate to the singleton for its implementation of the relevant methods.
If you can inherit it, it's not really a singleton, since each inherited class will have at least one instance.
However, you can just make the constructor protected.
I respectfully offer a counterpoint to the comments that suggest a singleton should not be subclassed. Subclassing a singleton is discussed in "Design Patterns: Elements of Reusable Object-Oriented Software" by Gamma, Helm, Johnson, and Vlissides (aka "The Gang of Four" book or "GOF" for short).
A properly subclassed singleton would also be a singleton. For example, suppose you have a singleton that handles logging informational messages called Logger. Now suppose you want to extend the functionality of Logger to write output using HTML tags. Let's call it HTMLLogger. Both of these classes are singletons, but one extends the functionality of the other.
First, here's a simple singleton and its test case:
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.simple;
public class SimpleSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static SimpleSingleton instance;
private int sampleValue;
public static SimpleSingleton getInstance() {
if (instance == null) {
instance = new SimpleSingleton();
}
return instance;
}
public int getSampleValue() {
return sampleValue;
}
public void setSampleValue(int sampleValue) {
this.sampleValue = sampleValue;
}
protected SimpleSingleton() {
// Insures construction cannot occur outside of class.
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.simple.test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import study.design.patterns.creational.singleton.simple.SimpleSingleton;
public class SimpleSingletonTest {
#Test
public void testIllegalCreation() {
// The following line will not compile because the constructor is not visible.
// Singleton instance = new Singleton();
}
#Test
public void testObjectEquality() {
SimpleSingleton instance1 = SimpleSingleton.getInstance();
assertNotNull(instance1);
SimpleSingleton instance2 = SimpleSingleton.getInstance();
assertNotNull(instance2);
assertEquals(instance1, instance2);
}
#Test
public void testDataEquality() {
SimpleSingleton instance1 = SimpleSingleton.getInstance();
assertNotNull(instance1);
SimpleSingleton instance2 = SimpleSingleton.getInstance();
assertNotNull(instance2);
assertEquals(instance1, instance2);
instance1.setSampleValue(5);
int testSampleValue = instance2.getSampleValue();
assertEquals(testSampleValue, 5);
}
}
/////////////////////////////////////////////////////////////////////////////
I've found four ways you can subclass a singleton.
Option 1. Brute force.
Essentially, the subclass reimplements the key features to make the class a singleton. That is, the static instance variable, the static getInstance method, and a hidden constructor. In this case, the hidden constructor calls the base class.
Here's a sample base class, subclass, and test case:
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassbruteforce;
// This singleton can be extended (subclassed)
public class BruteForceExtendableSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static BruteForceExtendableSingleton instance;
private int sampleValue;
public static BruteForceExtendableSingleton getInstance() {
// The problem with this version of an extendable singleton is clear from the code below - every subclass possible is hard-coded.
// Creating a new subclass requires modifying the base class as well, which violates the open-closed principle.
if (instance == null) {
instance = new BruteForceExtendableSingleton();
}
return instance;
}
public int getSampleValue() {
return sampleValue;
}
public void setSampleValue(int sampleValue) {
this.sampleValue = sampleValue;
}
protected BruteForceExtendableSingleton() {
// Insures construction cannot occur outside of class.
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassbruteforce;
public class BruteForceSubclassSingleton extends BruteForceExtendableSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static BruteForceSubclassSingleton instance;
private int sampleValue2;
public static BruteForceSubclassSingleton getInstance() {
// The problem with this version of an extendable singleton is clear from the code below - every subclass possible is hard-coded.
// Creating a new subclass requires modifying the base class as well, which violates the open-closed principle.
if (instance == null) {
instance = new BruteForceSubclassSingleton();
}
return instance;
}
public int getSampleValue2() {
return sampleValue2;
}
public void setSampleValue2(int sampleValue2) {
this.sampleValue2 = sampleValue2;
}
protected BruteForceSubclassSingleton() {
super();
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassbruteforce.test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import study.design.patterns.creational.singleton.subclassbruteforce.BruteForceExtendableSingleton;
import study.design.patterns.creational.singleton.subclassbruteforce.BruteForceSubclassSingleton;
public class BruteForceExtendableSingletonTest {
#Test
public void testIllegalCreation() {
// The following lines will not compile because the constructor is not visible.
// BruteForceExtendableSingleton instance = new BruteForceExtendableSingleton();
// BruteForceSubclassSingleton instance2 = new BruteForceSubclassSingleton();
}
#Test
public void testCreateBruteForceExtendableSingleton() {
BruteForceExtendableSingleton singleton = BruteForceExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is an ExtendableSingleton, but not a FixedSubclassSingleton.
assertTrue(singleton instanceof BruteForceExtendableSingleton);
assertFalse(singleton instanceof BruteForceSubclassSingleton);
}
#Test
public void testCreateBruteForceSubclassSingleton() {
BruteForceExtendableSingleton singleton = BruteForceSubclassSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is a BruteForceSubclassSingleton.
assertTrue(singleton instanceof BruteForceSubclassSingleton);
}
#Test
public void testCreateBothBruteForceSingletons() {
BruteForceExtendableSingleton singleton = BruteForceExtendableSingleton.getInstance();
assertNotNull(singleton);
assertTrue(singleton instanceof BruteForceExtendableSingleton);
assertFalse(singleton instanceof BruteForceSubclassSingleton);
BruteForceExtendableSingleton singleton2 = BruteForceSubclassSingleton.getInstance();
assertNotNull(singleton2);
assertTrue(singleton2 instanceof BruteForceSubclassSingleton);
assertFalse(singleton == singleton2);
}
}
/////////////////////////////////////////////////////////////////////////////
Pros:
Allows for both singletons to exist at the same time.
Cons:
Duplication of effort to create a singleton. The singleton nature of the subclass does not come from its base class.
If the singletons need to be separate, it's possible that a better design is needed to share the other methods instead of subclassing.
Option 2. Selecting from a fixed set of classes.
In this case, the getInstance method in the base class determines which instance to use based on a flag, such as a system property. In the code sample, I use the name of the class itself. Using a series of if blocks, the code decides how to initialize the instance.
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassfixed;
// This singleton can be extended (subclassed)
public class FixedExtendableSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static FixedExtendableSingleton instance;
private int sampleValue;
public static FixedExtendableSingleton getInstance() {
// The problem with this version of an extendable singleton is clear from the code below - every subclass possible is hard-coded.
// Creating a new subclass requires modifying the base class as well, which violates the open-closed principle.
if (instance == null) {
String singletonName = System.getProperty("study.design.patterns.creational.singleton.classname");
if (singletonName.equals(FixedExtendableSingleton.class.getSimpleName())) {
instance = new FixedExtendableSingleton();
} else if (singletonName.equals(FixedSubclassSingleton.class.getSimpleName())) {
instance = new FixedSubclassSingleton();
}
}
return instance;
}
public static void clearInstance() {
// This method wipes out the singleton.
// This is purely for testing purposes so getInstance can reconnect to a new singleton if needed.
instance = null;
}
public int getSampleValue() {
return sampleValue;
}
public void setSampleValue(int sampleValue) {
this.sampleValue = sampleValue;
}
protected FixedExtendableSingleton() {
// Insures construction cannot occur outside of class.
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassfixed;
public class FixedSubclassSingleton extends FixedExtendableSingleton {
private int sampleValue2;
public int getSampleValue2() {
return sampleValue2;
}
public void setSampleValue2(int sampleValue2) {
this.sampleValue2 = sampleValue2;
}
// Must be defined to prevent creation of a public default constructor.
protected FixedSubclassSingleton() {
super();
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassfixed.test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import study.design.patterns.creational.singleton.subclassfixed.FixedExtendableSingleton;
import study.design.patterns.creational.singleton.subclassfixed.FixedSubclassSingleton;
public class FixedExtendableSingletonTest {
#Test
public void testIllegalCreation() {
// The following lines will not compile because the constructor is not visible.
// ExtendableSingleton instance = new ExtendableSingleton();
// FixedSubclassSingleton instance = new FixedSubclassSingleton();
}
#Test
public void testCreateExtendableSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", "FixedExtendableSingleton");
FixedExtendableSingleton singleton = FixedExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is an ExtendableSingleton, but not a FixedSubclassSingleton.
assertTrue(singleton instanceof FixedExtendableSingleton);
assertFalse(singleton instanceof FixedSubclassSingleton);
}
#Test
public void testCreateFixedSubclassSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", "FixedSubclassSingleton");
FixedExtendableSingleton singleton = FixedExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is a FixedSubclassSingleton.
assertTrue(singleton instanceof FixedSubclassSingleton);
}
#AfterEach
protected void tearDown() {
FixedExtendableSingleton.clearInstance();
}
}
/////////////////////////////////////////////////////////////////////////////
Pros:
Clearer binding of subclass to singleton behavior.
Reduction of duplicate code.
Cons:
Only a fixed set of subclasses are defined. Adding a new subclass requires modifying the getInstance method.
Option 3. Determine which singleton to use from a dynamic set of classes.
This method attempts to remove the need to modify getInstance for every subclass. The idea is to include a registry (map) of names to singletons in the base class, and look up the correct one in getInstance.
In order to populate the registry with singletons, each singleton needs to be created beforehand. How is this done? According to GOF, we can assign a static variable to an instance of the object. When the class is loaded, the singleton is constructed, and the constructor adds the object to the registry. This is more complex, but it works (sort of).
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassflexible;
import java.util.HashMap;
import java.util.Map;
//This singleton can be extended (subclassed)
public class FlexibleExtendableSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static FlexibleExtendableSingleton instance;
// This must appear before thisSingleton, because the constructor requires the registry.
protected static Map<String, FlexibleExtendableSingleton> registry = new HashMap<String, FlexibleExtendableSingleton>();
// This singleton - each class in the hierarchy needs one of these. It will trigger construction (and therefore, registration).
private static FlexibleExtendableSingleton thisSingleton = new FlexibleExtendableSingleton();
public static void activateClass() {
// Do nothing special.
}
private int sampleValue;
protected static void register(String name, FlexibleExtendableSingleton singletonClass) {
registry.put(name, singletonClass);
}
protected static FlexibleExtendableSingleton lookupFromRegistry(String name) {
return registry.get(name);
}
public static FlexibleExtendableSingleton getInstance() {
if (instance == null) {
String singletonName = System.getProperty("study.design.patterns.creational.singleton.classname");
instance = lookupFromRegistry(singletonName);
}
return instance;
}
public static void clearInstance() {
// This method wipes out the singleton.
// This is purely for testing purposes so getInstance can reconnect to a new singleton if needed.
instance = null;
}
public int getSampleValue() {
return sampleValue;
}
public void setSampleValue(int sampleValue) {
this.sampleValue = sampleValue;
}
protected FlexibleExtendableSingleton() {
// Protected insures construction cannot occur outside of class.
// Register the class when it is constructed by its static method.
// Subclasses will be able to use this method as well.
register(this.getClass().getSimpleName(), this);
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassflexible;
import study.design.patterns.creational.singleton.subclassdynamicload.DynamicLoadExtendableSingleton;
public class FlexibleSubclassSingleton extends FlexibleExtendableSingleton {
// This singleton - each class in the hierarchy needs one of these. It will trigger construction (and therefore, registration).
private static FlexibleSubclassSingleton thisSingleton = new FlexibleSubclassSingleton();
private int sampleValue2;
public static void activateClass() {
// Do nothing special.
}
public int getSampleValue2() {
return sampleValue2;
}
public void setSampleValue2(int sampleValue2) {
this.sampleValue2 = sampleValue2;
}
// Must be defined to prevent creation of a public default constructor.
protected FlexibleSubclassSingleton() {
// The following line will also register the class.
super();
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassflexible.test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import study.design.patterns.creational.singleton.subclassflexible.FlexibleExtendableSingleton;
import study.design.patterns.creational.singleton.subclassflexible.FlexibleSubclassSingleton;
public class FlexibleExtendableSingletonTest {
#Test
public void testIllegalCreation() {
// The following lines will not compile because the constructor is not visible.
// FlexibleExtendableSingleton instance = new FlexibleExtendableSingleton();
// FlexibleSubclassSingleton instance2 = new FlexibleSubclassSingleton();
}
#Test
public void testCreateFlexibleExtendableSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", "FlexibleExtendableSingleton");
FlexibleExtendableSingleton.activateClass();
FlexibleSubclassSingleton.activateClass();
FlexibleExtendableSingleton singleton = FlexibleExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is an ExtendableSingleton, but not a FixedSubclassSingleton.
assertTrue(singleton instanceof FlexibleExtendableSingleton);
assertFalse(singleton instanceof FlexibleSubclassSingleton);
}
#Test
public void testCreateFlexibleSubclassSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", "FlexibleSubclassSingleton");
FlexibleExtendableSingleton.activateClass();
FlexibleSubclassSingleton.activateClass();
FlexibleExtendableSingleton singleton = FlexibleExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is a FlexibleSubclassSingleton.
assertTrue(singleton instanceof FlexibleSubclassSingleton);
}
#AfterEach
protected void tearDown() {
FlexibleExtendableSingleton.clearInstance();
}
}
/////////////////////////////////////////////////////////////////////////////
Notice the method "activateClass" in each of the singletons. This method is empty and appears to do nothing. In reality, it is there to trigger loading the class for the first time. When called, the class is loaded, which creates the static singleton instance, which adds the entry to the registry. If the class is not loaded, the registry will not be populated and getInstance will return null for any class except for the base class, because calling getInstance will also trigger loading the base class.
Alternatively, instead of using "activateClass" methods, you could use a ClassLoader to load all of the singleton classes. You would still need to explicitly load every singleton class.
Pros:
getInstance does not have to be modified each time.
Cons:
Every subclass requires an empty activateClass method (or another way to load the class), which must be called prior to getInstance. Since each singleton class must be activated, we didn't gain much improvement from Option 2.
Option 4. Dynamically loading the singleton by name.
In Option 3 above, we had the problem of loading the singleton classes to populate a registry. Since the selection of the singleton is already being controlled by a system property, why not just load the singleton class to be used and set that as the instance?
Using reflection, we can load the class by name, locate the static singleton (the "thisSingleton" field), and assign it to the instance.
NOTE: Reflection enables a developer to bypass encapsulation, so should be used with caution. In this case, its use is limited to getInstance.
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassdynamicload;
import java.lang.reflect.Field;
//This singleton can be extended (subclassed)
public class DynamicLoadExtendableSingleton {
// The instance - only one of these can exist in the system (currently not accounting for threads).
private static DynamicLoadExtendableSingleton instance;
// This singleton - each class in the hierarchy needs one of these. It will trigger construction (and therefore, registration).
private static DynamicLoadExtendableSingleton thisSingleton = new DynamicLoadExtendableSingleton();
private int sampleValue;
public static DynamicLoadExtendableSingleton getInstance() {
if (instance == null) {
String singletonName = System.getProperty("study.design.patterns.creational.singleton.classname");
ClassLoader loader = DynamicLoadExtendableSingleton.class.getClassLoader();
try {
Class<?> singletonClass = loader.loadClass(singletonName);
Field field = singletonClass.getDeclaredField("thisSingleton");
field.setAccessible(true);
instance = (DynamicLoadExtendableSingleton) field.get(null);
} catch (ClassNotFoundException e) {
// The class was not found.
// TODO: Add error handling code here.
} catch (NoSuchFieldException e) {
// The field does not exist - fix the singleton class to include thisSingleton field.
// TODO: Add error handling code here.
} catch (IllegalAccessException e) {
// Should not occur - we make the field accessible just for this purpose.
// TODO: Add error handling code here.
}
}
return instance;
}
public static void clearInstance() {
// This method wipes out the singleton.
// This is purely for testing purposes so getInstance can reconnect to a new singleton if needed.
instance = null;
}
public int getSampleValue() {
return sampleValue;
}
public void setSampleValue(int sampleValue) {
this.sampleValue = sampleValue;
}
protected DynamicLoadExtendableSingleton() {
// Protected insures construction cannot occur outside of class.
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassdynamicload;
public class DynamicLoadSubclassSingleton extends DynamicLoadExtendableSingleton {
// This singleton - each class in the hierarchy needs one of these. It will trigger construction (and therefore, registration).
private static DynamicLoadSubclassSingleton thisSingleton = new DynamicLoadSubclassSingleton();
private int sampleValue2;
public int getSampleValue2() {
return sampleValue2;
}
public void setSampleValue2(int sampleValue2) {
this.sampleValue2 = sampleValue2;
}
// Must be defined to prevent creation of a public default constructor.
protected DynamicLoadSubclassSingleton() {
super();
}
}
/////////////////////////////////////////////////////////////////////////////
package study.design.patterns.creational.singleton.subclassdynamicload.test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import study.design.patterns.creational.singleton.subclassdynamicload.DynamicLoadExtendableSingleton;
import study.design.patterns.creational.singleton.subclassdynamicload.DynamicLoadSubclassSingleton;
public class DynamicLoadExtendableSingletonTest {
#Test
public void testIllegalCreation() {
// The following lines will not compile because the constructor is not visible.
// DynamicLoadExtendableSingleton instance = new DynamicLoadExtendableSingleton();
// DynamicLoadSubclassSingleton instance2 = new DynamicLoadSubclassSingleton();
}
#Test
public void testCreateDynamicLoadExtendableSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", DynamicLoadExtendableSingleton.class.getName());
DynamicLoadExtendableSingleton singleton = DynamicLoadExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is an ExtendableSingleton, but not a FixedSubclassSingleton.
assertTrue(singleton instanceof DynamicLoadExtendableSingleton);
assertFalse(singleton instanceof DynamicLoadSubclassSingleton);
}
#Test
public void testCreateDynamicLoadSubclassSingleton() {
System.setProperty("study.design.patterns.creational.singleton.classname", DynamicLoadSubclassSingleton.class.getName());
DynamicLoadExtendableSingleton singleton = DynamicLoadExtendableSingleton.getInstance();
assertNotNull(singleton);
// Check that the singleton is a DynamicLoadSubclassSingleton.
assertTrue(singleton instanceof DynamicLoadSubclassSingleton);
}
#AfterEach
protected void tearDown() {
DynamicLoadExtendableSingleton.clearInstance();
}
}
/////////////////////////////////////////////////////////////////////////////
Pros:
Subclasses do not require a method to activate the class. The only code required is a "thisSingleton" field.
The getInstance method does not require modification for each new subclass.
Cons:
Reflection can be slower, but since it's only used in one place and only when the singleton is assigned, the risk is minimal.
It's possible to get an error if the class name is incorrect. Again, this is a minimal risk.
In summary, while subclassing a singleton may not be common, it is addressed in the GOF book as feasible. There are a few ways to support subclassing singletons, each with benefits and drawbacks. Some of the methods listed above come directly from the book. The method of using reflection was my addition.
Are you looking to provide some inheritable behavior to a number of singleton's? If so, perhaps you could move that code into an abstract class.
As SLaks pointed out, extending a singleton would no longer make it a singleton pattern.