How to refactor inner class MouseAdapter? - java

Suppose I have a file like this:
import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
public class Foo extends JPanel
{
private int m;
private int n;
private int o;
public Foo()
{
this.addMouseListener(new Bar());
}
class Bar extends MouseAdapter
{
// ...
// methods here access and modify values of the private
// instance variables.
// ...
}
}
Obviously I can add simple accessors and mutators to Foo but that gets tedious fast and completely breaks encapsulation. How can I refactor this inner class while keeping damage to encapsulation to a minimum?

If these classes seem too big, then you should split them. The first step in splitting them would be to stop relying on private instance variables of the outer class. You could, as you say, add public getters and setters, but better would be to have Foo implement a public interface of Bar, and have Bar simply talk to that interface. And initialize each Bar with self.
public class Bar extends MouseAdapter {
public interface Caller {
void thingClicked();
...
}
}
public class Foo extends JPanel implements Bar.Caller {
...
}
So where now in Bar you have something like:
public void mouseUp() {
m = m + 1;
n = 0
}
you would now have
public void mouseUp() {
caller.thingClicked();
}
and, in Foo:
public void thingClicked() {
m = m + 1;
n = 0
}
It's hard to make this clear without more specifics, but basically your outer class is responding to messages, and the mouse listener is only responsible for delivering those messages, not for what happens in response to them. In the examples above it looks like this is more code than what you already have, but I suspect you'll find that slicing it out in this way ultimately leads to less code - and certainly code which is easier to test and reuse.

One approach is to put the class bar in a new file and inject everything you need there into the constructor. You'd need to change your primitive types like int into objects like Integer. Then you can create a Builder class that steers the construction of Foo and Bar. Let's assume for simplicity you need the same instance of Baz in all of your Foo and Bar instances:
class Builder {
// objects that both classes need are stored as member variables
// if you need multiple instances of baz you can also store a BazBuilder here
private Baz baz;
public Builder(Baz baz) {
this.baz=baz;
}
public Foo buildFoo() {
Foo foo = new Foo(baz);
return foo;
}
public Bar buildBar() {
Bar bar = new Bar(baz);
return bar;
}
}
This is only a minimalistic example but it's easy to extend. Builder#buildFoo() could take arguments that are needed in the constructor of Foo and likewise for Bar.
EDIT
Small example of what it might look like with a BazBuilder:
class BazBuilder {
Baz build(int value) {
return new Baz(value);
}
}
And in Builder you can use it like so:
class Builder {
private BazBuilder bazBuilder;
public Build(BazBuilder bazBuilder) {
this.bazBuilder = bazBuilder;
}
public Foo buildFoo() {
Baz baz = bazBuilder.build(5);
Bar bar = new Bar(baz);
Foo foo = new Foo(baz);
foo.add(bar);
return foo;
}
}

Related

Best way in Java to hide public setters from client applications

I have a Spring Application which is built on top of DynamoDB. I am trying to write a saveFoo() Repository method that will save an object of type Foo to the database. This method will be called from the application layer.
What I'm struggling with is that the Foo class has fields within it that are Dynamo specific. I don't want clients of the saveFoo() class to think they need to create an object of type Foo with these fields. Nor do I want them to attempt to ever set these values themselves.
These database-specific fields need public getters and setters in order to work with the DynamoDB SDK.
The database model class looks like the following:
#DynamoDBTable(tableName = "foo")
public class Foo {
// Fields the client should be setting
private String bar;
private String baz;
// Fields the client should not access and should not care about. They are internal fields used for DynamoDB purposes.
private Long version;
private String gsiIndexKey;
// Empty constructor needed for deserialization of data from dynamodb
public Foo() {
}
// Getters and setters for all of the above fields.
}
And the repository method to save the object to the DB:
public class FooRepositoryImpl {
public Foo saveFoo(WhatClassShouldThisBe foo) {
// Code that saves a new Foo item to the database and returns it.
}
}
My current idea is to create a FooWrapper interface that the saveFoo() method can take as a parameter. The wrapper will allow the client to set the fields that they should have control over, but does not expose fields related to the database internals. Something like the below:
/**
* Allows us restrict visibility of the Foo fields to the Application by hiding database internal fields.
**/
public interface FooWrapper {
Foo getFoo()
}
public class FooWrapperImpl implements FooWrapper {
private final Foo foo;
public FooWrapperImpl(String bar, String baz) {
foo = new Foo();
foo.setBar(bar);
foo.setBaz(baz);
}
#Override
public Foo getFoo() {
return foo;
}
}
public class FooRepositoryImpl {
public Foo saveFoo(FooWrapper fooWrapper) {
Foo foo = fooWrapper.getFoo(); // Save this item to db
// Code that saves a new Foo item to the database and returns it.
}
}
What are your thoughts on this approach? Does anyone know of some better techniques I could try? I can't help but feel that I am over-engineering things here.
Expose only an interface to clients that has the methods you want. Internally you can call the other public methods of the implementation, but the client code won't know them.
If you are using modern Java, don't export your implementation classes outside of your module. Only export the public interface.
You could also keep an interface for internal use that has more methods than the public API.
public interface Foo {
public void setBar(String bar);
public void setBaz(String baz);
}
#DynamoDBTable(tableName = "foo")
public class FooImpl implements Foo {
// Fields the client should be setting
private String bar;
private String baz;
// Fields the client should not access and should not care about. They are internal fields used for DynamoDB purposes.
private Long version;
private String gsiIndexKey;
// Empty constructor needed for deserialization of data from dynamodb
public FooImpl() {
}
// Getters and setters for all of the above fields.
#Override
public void setBar(String bar) {
this.bar = bar;
}
#Override
public void setBaz(String baz) {
this.baz = bar;
}
// Not part of the Foo interface
public void setVersion(Long version) {
this.version = version;
}
public void setGsiIndexKey(String indexKey) {
this.gsiIndexKey = indexKey;
}
}

How to create a new object based on interface implementation

Firstly, I believe my question is badly worded but don't really understand how to phrase it.
I have a starting interface that is being implemented by a number of classes. What I want to do is to see if there is a way to create a new object such that I am being passed the generic interface, then based on the method .getClass().getSimpleName(), create a new object based on that string.
Is the only way to create a switch case statement? As the number of implementing classes are too many (about 100 or so).
Reference code:
public interface MyInterface {
public void someMethod();
}
then I would have my implementing classes:
public class MyClass1 implements MyInterface {
public void someMethod() { //statements }
}
public class MyClass2 implements MyInterface {
public void someMethod() { //statements }
}
public class MyClass3 implements MyInterface {
public void someMethod() { //statements }
}
What I want to have in the end is another class which is passed an argument of type MyInterface, get the simple name from that and create a new instance of MyClassX based on that simple name.
public class AnotherClass {
public void someMethod(MyInterface interface) {
if (interface == null) {
System.err.println("Invalid reference!");
System.exit(-1);
} else {
String interfaceName = interface.getClass().getSimpleName();
/**
* This is where my problem is!
*/
MyInterface newInterface = new <interfaceName> // where interfaceName would be MyClass1 or 2 or 3...
}
}
}
Any help is highly appreciated!
You can use reflection for this:
public void someMethod(MyInterface myInterface) {
Class<MyInterface> cl = myInterface.getClass();
MyInteface realImplementationObject = cl.newInstance(); // handle exceptions in try/catch block
}
This is a common problem with many solutions. When I face it, I never use reflection because it is difficult to maintain if it is part of a big project.
Typically this problem comes when you have to build an object based on a user selection. You can try a Decorator pattern for that. So, instead of building a different object for each option. You can build a single object adding functionality depending on a selection. For instance:
// you have
Pizza defaultPizza = new BoringPizza();
// user add some ingredients
Pizza commonPizza = new WithCheese(defaultPizza);
// more interesting pizza
Pizza myFavorite = new WithMushroom(commonPizza);
// and so on ...
// then, when the user checks the ingredients, he will see what he ordered:
pizza.ingredients();
// this should show cheese, mushroom, etc.
under the hood:
class WithMushroom implements Pizza {
private final Pizza decorated;
public WithMushroom(Pizza decorated) {
this.decorated = decorated;
}
#Override
public Lizt<String> ingredients() {
List<String> pizzaIngredients = this.decorated.ingredients();
// add the new ingredient
pizzaIngredients.add("Mushroom");
// return the ingredients with the new one
return pizzaIngredients;
}
}
The point is that you are not creating an object for each option. Instead, you create a single object with the required functionality. And each decorator encapsulates a single functionality.

Test a factory of a 3rd party class

My application uses a third party jar (no access to source, etc.) I have a factory that creates an object (call it Foo) correctly from settings, i.e.
public FooFactoryImpl implements FooFactory {
private final Settings settings;
private final OtherDependency other;
#Inject
public FooFactoryImpl(Settings settings, OtherDependency other) {
this.settings = settings;
this.other = other;
}
public Foo create(String theirArg) {
Foo newFoo = new Foo(theirArg); // there is no no-arg constructor
// This isn't exactly the way I do it but this is shorter and close enough
newFoo.setParamOne(settings.get("ParamOne"));
newFoo.setParamTwo(settings.get("ParamTwo"));
// etc.
}
}
I would like to unit test this factory using Mockito - make sure the created object is configured correctly. But of course, I run into this problem; that is, because my factory calls new, I can't inject a spy.
One possible solution is to introduce something like:
public FooFactoryDumb implements FooFactory {
public Foo create(String theirArg) {
return new Foo(theirArg);
}
}
And then something like:
public FooFactoryImpl implements FooFactory {
#Inject #Dumb private FooFactory inner;
// snip, see above
public create(String theirArg) {
Foo newFoo = inner.create(theirArg);
// etc.
}
}
This seems like a lot of boilerplate code just to enable unit testing. It smells bad to me, but I might be wrong. Is there a better way?
There is a similar but simpler way to do it: add a protected method to your factory to create a Foo:
protected Foo create(String theirArg){
return new Foo(theirArg);
}
then in your tests of your Factory, create a Test Double of your FactoryImpl and override the create method:
private class FooFactoryImplTestDouble extends FooFactoryImpl{
...
#Override
protected Foo create(String theirArg){
//create and return your spy here
}
}
Create a new class:
public class FooFactory3rd {
public Foo create3rdParty(String theirArg) {
return new Foo(theirArg);
}
}
Then change your class to:
public FooFactoryImpl implements FooFactory {
private final Settings settings;
private final OtherDependency other;
private final FooFactory3rd fooFactory3rd;
#Inject
public FooFactoryImpl(Settings settings, OtherDependency other, FooFactory3rd fooFactory3rd) {
this.settings = settings;
this.other = other;
this.fooFactory3rd = fooFactory3rd;
}
public Foo create(String theirArg) {
Foo newFoo = fooFactory3rd.create3rdParty(theirArg);
// This isn't exactly the way I do it but this is shorter and close enough
newFoo.setParamOne(settings.get("ParamOne"));
newFoo.setParamTwo(settings.get("ParamTwo"));
// etc.
}
}
And in your test code:
Foo fooMock = mock(Foo.class);
FooFactory3rd fooFactory3rdMock = mock(FooFactory3rd.class);
when(fooFactory3rdMock.create3rdParty(any(String.class)).thenReturn(fooMock);
FooFactoryImpl fooFactoryImpl = new FooFactoryImpl(settings, other, fooFactory3rdMock);
fooFactoryImpl.create("any string");
This way, you can inject your fooMock. When you call fooFactoryImpl.create("any string"), your mocked Foo is called under the cover.
Or if you want to go further clean, don't even need the constructor arg of FooFactory3rd. Just declare
private final FooFactory3rd fooFactory3rd = new FooFactory3rd();
And in your test, use reflection to change it to the mocked FooFactory3rd.
Well, it turns out that I had to use PowerMock anyway because the third party's methods were final. Since I'm already using PowerMock, I realized I can just do this:
#Before
public void setUp() throws Exception {
Foo toReturn = PowerMockito.mock(Foo.class);
PowerMockito.whenNew(Foo.class).withAnyArguments().thenReturn(toReturn);
}
And then I don't have to touch my original class at all.
Note: If you do this, you have to prepare both classes for PowerMock, i.e. do
#PrepareForTest( { Foo.class, FooFactoryImpl.class } )
Take a step back and think about what the contract of FooFactoryImpl is. It is that it must create a fully functional Foo, whatever that means. So if the contract of a Foo is that it does X, Y and Z, then the contract of a FooFactoryImpl is that it creates objects that do X, Y and Z.
This is a case for the kind of test in which the SUT consists of more than one class. I don't care whether you call this a unit test, an integration test, a subsystem test, a collaboration test, or some other name. The point is that the only meaningful test of FooFactoryImpl is a test that tests Foo as well. Instead of writing a test class for Foo alone, write a test class that tests the two classes jointly.
So, if the contract of Foo is to do X, Y and Z, then your test cases will do the following things with a FooFactoryImpl.
Call create and test that the created object does X.
Call create and test that the created object does Y.
Call create and test that the created object does Z.
I believe this is the only sensible way to attack this problem. The hard part is coming up with a convincing name for the test class.

java thread safe code + an atomic method question

I have a class Manager that is going to be accessed by multiple threads at the same time, I want to know if I did it the right way ?
also I think I need RemoveFoo to be atomic, but I'm not sure
public class Manager
{
private ConcurrentHashMap<String, Foo> foos;
//init in constructor
public RemoveFoo(String name)
{
Foo foo = foos.Get(name);
foo.RemoveAll();
foos.Remove(name);
}
public AddFoo(Foo foo)
{...}
}
public class Foo
{
private Map<String,Bar> bars;
//intialize it in constructor
//same for RemoveBar
public void AddBar(Bar bar)
{
synchronized(this)
{
bars.put(bar.id, bar);
}
}
public void RemoveAll()
{
synchronized(this)
{
//some before removall logic for each one
bars.remove(bar.id, bar);
}
}
}
public class Bar
{}
You do not need synchronised methods as you are using a ConcurrentHashMap, however be aware that Foo foo = foos.Get(name) could return null as another thread could already have removed the entry from the map.
Members can be declared as Map<String, Foo> foos, but must be initialsed as foos = new ConcurrentHashMap<String, Foo>;
RemoveFoo could be problematic. I suggest to use:
Foo foo = foos.remove (name);
if (foo != null) foo.removeAll();
instead. This makes sure that the map doesn't change between get() and remove().
In Foo, it's enough to synchronize on bars instead of the whole instance. But that's just a minor optimization.
Declare RemoveFoo(String) as synchronized:
public synchronized void RemoveFoo(String name) {
…
}
Also, be advised of the following:
method names should be lower case, e.g. removeFoo instead of RemoveFoo. This is not C#. :)
Every method needs a return type: public removeFoo() is not a valid method declaration, it needs to be public void removeFoo().
If you use a concurrentHashMap in Foo like
private Map<String,Bar> bars = new ConcurrentHashMap<String, Bar>();
maybe you can do away with the synchronization in Foo as well.
I am not sure what you are going to do on Foo and Bar, but it looks like a pattern of deallocation.
If they are not referenced by others, just call foos.Remove(name); and let GC engine handle the deallocation.

Refactoring classes that use global variables

I'm working on some classes that get part of their configuration from global variables, e.g.
class MyClass {
public void MyClass(Hashtable<String, String> params) {
this.foo = GlobalClass.GLOBALVAR.get("foo");
this.bar = GlobalClass.GLOBALVAR.get("bar");
this.params = params;
}
}
This is bad for a couple of reasons, GLOBALVAR talks to a database to get some of the variables and this makes it really hard to make unit tests. The other problem is that I have many (dozens) of classes that inherit from MyClass, so I can't easily change the constructor signature.
My current solution is to create an additional default constructor and setter methods for params, foo and bar.
class MyClass {
// Other code still here for backwards compatibility.
public void MyClass() {
// Do nothing much.
}
public void setParams(Hashtable<String, String> params) {
this.params = params;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
Any ideas on a good way to refactor this, besides the way I did it? My other thought would be to use a factory method, but I'm afraid I'll run into polymorphic substitution problems.
I think I would start by doing the following. It let's your existing code work without modification, and allows you to add new constructors to the subclasses as you can. Once all of the subclasses have the new constructor, and all of the calls to the old constructors are gone, you can get rid of the GlobalClass and the constructors that use it. You can also then, hopefully, work on cleaning up the GLOBALVAR (the Car class in my code).
import java.util.Hashtable;
class MyClass
{
private final Foo foo;
private final Bar bar;
private final Hashtable<String, String> params;
public MyClass(final Hashtable<String, String> params)
{
this(params, GlobalClass.GLOBALVAR);
}
// added constructor
public MyClass(final Hashtable<String, String> params,
final FooBar fooBar)
{
this.foo = fooBar.getFoo();
this.bar = fooBar.getBar();
this.params = params;
}
}
class MySubClass
extends MyClass
{
public MySubClass(final Hashtable<String, String> params)
{
super(params);
}
// added constructor
public MySubClass(final Hashtable<String, String> params,
final FooBar fooBar)
{
super(params, fooBar);
}
}
// unchanged
class GlobalClass
{
public static Car GLOBALVAR;
}
// added interface
interface FooBar
{
Foo getFoo();
Bar getBar();
}
class Car
// added implements
implements FooBar
{
private Foo foo = new Foo();
private Bar bar = new Bar();
public Object get(final String name)
{
if(name.equals("foo"))
{
return (foo);
}
if(name.equals("bar"))
{
return (bar);
}
throw new Error();
}
// added method
public Foo getFoo()
{
return ((Foo)get("foo"));
}
// added method
public Bar getBar()
{
return ((Bar)get("bar"));
}
}
// unchanged
class Foo
{
}
// unchanged
class Bar
{
}
I think you should introduce an interface to put a layer of abstraction between the global variable collection and its consumers.
interface GlobalVars {
String get(String key);
}
You should introduce a constructor with limited scope, probably package-private
MyClass(GlobalVars globals, Map<String, String> params) {
// create the object
}
And then provide public static factory methods to use this constructor.
public static MyClass newMyClass(Map<String, String> params) {
return new MyClass(GlobalClass.GLOBAL_VAR, params);
}
With this design you can pass in a mock implementation of GlobalVars in a unit test from within the same package by explicitly invoking the constructor.
Addendum: Since params seems to be a required field, I would definitely make it final and avoid the approach where you add mutators to overwrite them.
private final Map<String, String> params;
Also, make a defensive copy to prevent l33t h4x.
this.params = Collections.unmodifiableMap(params);
Your class should take all of its dependencies in the constructor. It's a good idea to make it impossible to create an invalid or uninitialized instance of classes. Make foo and bar private and final, and set them in the constructor.
A slight variation on your approach would be to have an object of type GLOBALVAR in the class and use that instead of the actual global (that refactoring should be a simple search/replace). You can default the new variable to the actual global variable and provide an override for testing.
This GlobalClass.GLOBALVAR should be chopped up up into logical units. That way it would be easier to make mock objects for the unit tests. For example in my CAD/CAM metal cutting application I have a MaterialList, a SheetSizeList, PartNestingParameters, etc.
I don't have a huge list of variables stuff into one giant AppParameter class. They all hang off a ShopStandards object. For Unit Test involving a specific PartNestingParmeters I will just go ShopStandards.PartNestingParmeters = new MockPartNestingParameterTest114(). The test will run not realizing that the Part Nesting Parameters are a mockup. Plus this save me from having to doing dozens of assignments just to get the ShopStandard setup correctly for the test.
We have even more automated where many of the Mock load from files saved during the test run during initial development.
Since you mention that you have the freedom to modify the class hierarchy.
Change the base MyClass ctor to take in 3 parameters params, foo and bar. Comment out the GlobalVar references and simply cache passed in values
Compile.. this should throw up a bunch of compile errors - no ctor which takes 1 parameter.
Fix each one to pass in GlobalVar.get("foo") and GlobalVar.get("bar"). Get it to build.
Refine: Now minimize hits to the DB by lazy load and caching the foo and bar values. Expose via some property on GlobalVar.

Categories

Resources