I have 4 custom spinners which modify the width, height, X location and Y location of one selected widget. My widget can be dragged around the screen, and the idea is to use these spinners to change certain properties such as width or height, and see immediate effect on the changes. Is there a pattern that I can use to replace all these classes (XSpinnerListener, YSpinnerListener...) with only one and indicate which property of my current object (a JButton) needs to change? Is this a good design approach?
public void init(){
widthSpinner.setListener(new WidthSpinnerListener());
heightSpinner.setListener(new HeightSpinnerListener());
xSpinner.setListener(new XSpinnerListener());
ySpinner.setListener(new YSpinnerListener());
}
public class XSpinnerListener implements SpinnerListener {
@Override
public void spinnerValueChanged() {
current.setLocation(xSpinner.getValue(), current.getY());
}
}
public class YSpinnerListener implements SpinnerListener {
@Override
public void spinnerValueChanged() {
current.setLocation(current.getX(), ySpinner.getValue());
}
}
public class WidthSpinnerListener implements SpinnerListener {
@Override
public void spinnerValueChanged() {
current.setSize(widthSpinner.getValue(), current.getHeight());
}
}
public class HeightSpinnerListener implements SpinnerListener {
@Override
public void spinnerValueChanged() {
current.setSize(current.getWidth(), heightSpinner.getValue());
}
}
Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
Decorator design pattern is used to modify the functionality of an object at runtime. At the same time other instances of the same class will not be affected by this, so individual object gets the modified behavior.
The Singleton Design Pattern is a Creational pattern, whose objective is to create only one instance of a class and to provide only one global access point to that object.
Some musings...
You could emulate Swing's design by giving your SpinnerListener spinnerValueChanged(...)
method a SpinnerEvent parameter, one that indicated which axis is being changed. The Axis could be encapsulated by an enum,...
enum Axis {
X("X"), Y("Y"), WIDTH("Width"), HEIGHT("Height");
private String name;
private Axis(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And the SpinnerEvent parameter class could look something like:
class SpinnerEvent {
private Object source;
private Axis axis;
private int value;
public SpinnerEvent(Object source, Axis axis, int value) {
this.source = source;
this.axis = axis;
this.value = value;
}
public Object getSource() {
return source;
}
public Axis getAxis() {
return axis;
}
public int getValue() {
return value;
}
}
Your SpinnerListener interface (which you don't show us) would have to change:
interface SpinnerListener {
public void SpinnerValueChanged(SpinnerEvent e);
}
And perhaps your concrete implementations could work on objects that implement a Movable interface:
interface Movable {
public abstract int getX();
public abstract void setX(int x);
public abstract int getY();
public abstract void setY(int y);
public abstract int getWidth();
public abstract void setWidth(int width);
public abstract int getHeight();
public abstract void setHeight(int height);
public abstract void move(Axis axis, int value);
}
with a key method, move that could be implemented like so:
@Override
public void move(Axis axis, int value) {
switch (axis) {
case X:
x += value;
break;
case Y:
y += value;
break;
case WIDTH:
width += value;
break;
case HEIGHT:
height += value;
default:
break;
}
}
Small concrete implementation
class ConcreteSpinnerListener implements SpinnerListener {
private Movable movable;
public ConcreteSpinnerListener(Movable movable) {
this.movable = movable;
}
@Override
public void SpinnerValueChanged(SpinnerEvent e) {
movable.move(e.getAxis(), e.getValue());
}
}
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