Right way to prevent subclass instantiation without calling a desired initialisation method? - java

Can somebody help a novice programmer to understand if his solution is correct?
My question is similar to the the following two:
What's wrong with overridable method calls in constructors?
Factory pattern in C#: How to ensure an object instance can only be created by a factory class?
Problem: I want to have subclasses which will differ only in their initialisation method. However, I also want to prevent instantiating these classes without initialization. In other words, I want to ensure, that some "initialize()" method will always be called after instantiation of a subclass:
public abstract class Data {
protected Parameter dataSource;
Data(parameter1){
this.dataSource = parameter1;
loadData(); // should be called to initialise class fields and ensure correct work of other class methods
}
protected abstract loadData(){
... //uses dataSource
}
}
So I decided to perform initialization on a constructor. It worked (now I know that it's a very bad practice) until I created a subclass where the initialize method used some additional parameters:
public class DataFromSpecificSources extends Data {
private Parameter dataSource2;
public DataFromSpecificSources(parameter1, parameter2){
this.dataSource2 = parameter2; // I can't put it here because the constructor is not called yet
super(parameter1); // this, of course, will not work
}
#Override
private void loadData(){
... // uses both dataSource 1 and 2
// or just dataSource2
}
}
This, of course, is not going to work. And I started searching for a right pattern... After I read the answers on questions posted before, I decided to use the factory and limit visibility of the subclass constructor to the package:
My solution:
// factory ensures that loadData() method will be called
public class MyDataFactory(){
public Data createSubClass(parameter1,parameter2){
Data subClass;
if (parameter2 != null){
subClass = new DataFromSpecificSources(parameter1, parameter2);
subClass.loadData();
} else {
subClass = new AnotherSubClass(parameter1);
subClass.loadData()
}
return subClass;
}
}
public abstract class Data {
protected Parameter dataSource;
Data(parameter1){
this.dataSource = parameter1;
}
// I don't call it in constructor anymore - instead it's controlled within the factory
protected abstract loadData(){
... //uses dataSource
}
}
public class DataFromSpecificSources {
private Parameter dataSource2;
protected DataFromSpecificSources(){}
// now this constructor is only visible within package (only for the factory in the same package)
DataFromSpecificSources(parameter1, parameter2){
super(parameter1); // it does not initialise data anymore
this.dataSource2 = parameter2;
}
#Override
protected void loadData(){
... // uses dataSources 1 and 2
}
}
Now factory ensures that subclasses will be initialized (data will be loaded) and instantiation of subclasses is not allowed in other packages. Other classes have no access to constructor of subclasses and are forced to use factory to get an instance of a subclass.
I just wanted to ask if my solution is correct (logically) and Factory method with subclass constructor visibility limited to the package is right choice here?! Or there is any other more effective pattern solving the problem?!

Using a factory is definitely a step in the right direction. The issue I see is that what happens when you want to add a third class that takes a third parameter. Now your Factory is either going to have to have a second overloaded createSubClass method taking the third parameter, or all your code is going to have to be rewritten to provide the third parameter. Additionally you are forcing anyone using the Factory to specify null for the second parameter even if they only want the single parameter class.... when you get to the class that takes 15 parameters how are you going to remember which parameter is which
The solution to this is to use the Builder pattern instead.
public class MyDataBuilder(){
private parameter1 = null;
private parameter2 = null;
public MyDataBuilder withParameter1(parameter1) {
this.parameter1 = parameter1;
return this;
}
public MyDataBuilder withParameter2(parameter2) {
this.parameter2 = parameter2;
return this;
}
public Data createSubClass(){
Data subClass;
if (parameter2 != null){
subClass = new DataFromSpecificSources(parameter1, parameter2);
} else {
subClass = new AnotherSubClass(parameter1);
}
subClass.loadData();
return subClass;
}
}
Now the code creating the Data instances can work like so:
Data data = new MyDataBuilder().withParameter1(param1).withParameter2(param2).create();
or
Data data = new MyDataBuilder().withParameter1(param1).create();
And that code is future-proofed for when you add parameter3... and you can even have the builder with a non-null default for parameter3 if you so need that.
The next thing you notice is that you now have this nice Builder object that contains all the required parameters... so now you can add getters to the Builder and just pass the Builder as the constructor parameter, e.g.
public class DataFromSpecificSources {
...
DataFromSpecificSources(MyDataBuilder builder){
...
}
...
}
So that you now almost have a standard constructor signature
Now for some Java specific improvements. We can make the builder not need to know about the sub-classes at all!
Using a DI framework we can inject the classes that implement the Data interface / abstract class into the Builder and then just iterate through each class until we find a class that supports the configuration of the Builder instance.
The poor-man's DI framework is the /META-INF/services contract and the ServiceLoader class available since JRE 1.6 (though the core logic has been in Java since 1.2)
Your builder's create method will then look a little something like
public Data create() {
for (DataFactory factory: ServiceLoader.load(DataFactory.class)) {
if (factory.canCreate(this)) {
Data result = factory.newInstance(this);
result.loadData();
return result;
}
}
throw new IllegalStateException("not even the default instance supports this config");
}
Whether you want to go to that extreme is questionable... but since you might come across it at some point in time when looking at other people's code, it is probably a good time to point it out to you now.
Oh, the reason why we have to add a Factory class to be looked up by the ServiceLoader is because ServiceLoader expects to call the default constructor, and we have hidden the default constructor so we use a Factory class to do the work for us and allow us to keep the constructor hidden.
There is nothing preventing the Factory classes from being static inner classes in the Data classes (which gives them great visibility on the class they are creating), e.g.
public class UberData extends Data {
private UberData(MyDataBuilder config) {
...
}
public static class Factory extends DataFactory {
protected Data create(MyDataBuilder config) {
return new UberData(config);
}
protected boolean canCreate(MyDataBuilder config) {
return config.hasFlanges() and config.getWidgetCount() < 7;
}
}
}
As we can then list in META-INF/services/com.mypackage.DataFactory
com.mypackage.UberData.Factory
com.mypackage.DataFromSpecificSources.Factory
com.some.otherpackage.AnotherSubClass.Factory
The best bit about this type of solution is it allows adding additional implementations just by adding those implementations to the classpath at run-time... i.e. very loose coupling

Related

Interface to enforce generic static method in Java

I have a Java class Model which models some data from my remote database. I want all data models in my project to be able to supply a builder from a Map<String, Object> instance (in practice, I'm working with SnapshotParser<Model> parsers with Firestore, but I'll just call getData() in every model). This should look something like:
public class Model {
private String name;
public Model(String name) { this.name = name; }
public static SnapshotParser<Model> getDocParser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"));
};
}
}
Note that I'll have several models (Model2, Model3...) which will also be required to provide such an interface. To enforce this behavior, I created a DocParserSupplier generic class for my model classes to implement:
public interface DocParserSupplier<T> {
static SnapshotParser<T> getDocParser();
}
This doesn't work for two reasons (as Android Studio informs me):
static methods of interfaces must have a default implementation. I can't do that without knowing T.
I get the "T cannot be referenced in static context" error.
If remove the static keyword from the above interface, I can do what I want but it would require I create an actual instance of the Model to get the parser. It would work but it makes more sense if the method is static.
Is there a Java way to do what I want?
EDIT: My specific use case is in matching RecyclerViews to documents in my database. Constructing the FirestoreRecyclerOptions object requires a parser to convert key-value data to a Model:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
Interfaces enforce behavior of instances, so that references to any object which has that behavior can be passed around in a type-safe way. Static methods on the other hand, don't belong to any particular instance of an object; the class name is essentially just a namespace. If you want to enforce behavior, you will have to create an instance somewhere (or use reflection, if it is absolutely necessary to ensure a class has a particular static method).
Unless this system is going to be opened up for extension, where others can define their own models, I would say ditch the DocParserSupplier interface altogether and call the static methods exactly as you are now, or factor them out into a factory interface + implementation. The factory option is nice because you can replace the production implementation with a fake implementation that returns dummy parsers for tests.
Edit: Doc Parser Factory
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
...
// The implementation of each getModelXParser method
class DocParserFactoryImpl {
SnapshotParser<Model1> getModel1Parser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"))};
}
...
}
...
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}
It's not so much to do with static or non-static, as it is with the fact that you cannot create an instance of a generic object without passing the type parameter(s) one way or another. In fact, I answered a similar question a few days ago, when somebody wanted to use enums to get the required builder.
In short, you cannot write a method <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) (or, in this case, <T extends AbstractBuilder> T builder()) without passing T in some form. Even though it will make sense at runtime, the compiler can't figure out what generic type to use if you don't tell it which one it is.
In Java 8, you can solve this elegantly with method references. I don't know much about Android, but I believe you're still on Java 6 there, so this wouldn't work.
Anyway, you can have something like the following:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
.setQuery(query1, Model1.getDocParser())
.build();
It's not exactly what you want, but the way you're trying to go about it will not work.

How to design Java class(es) that can optionally function as Singleton?

Here's the scenario:
public class A {
public A {}
void doSomething() {
// do something here...
}
}
Right now, the class is setup where you can create multiple instances. But I also see a need where I might want to restrict the class to only one instance, i.e. Singleton class.
The problem is I'm not sure how to go about the design of accomplishing both goals: Multiple instances and one instance. It doesn't sound possible to do in just one class. I imagine I'll need to use a derived class, an abstract class, interface, something else, or some combination.
Should I create class A as a base class and create a derived class which functions as the singleton class?
Of course, the first thing should always be to question the necessity to use singletons. But sometimes, they are simply a pragmatic way to solve certain problems.
If so, the first thing to understand is: there is no solution that can "enforce" your requirements and prevent mis-use, but here is a "pattern" that helps a lot by turning "intentions" into "meaningful" code:
First, I have an interface that denotes the functionality:
interface WhateverService { void foo() }
Then, I have some impl for that:
class WhateverServiceImpl implements WhateverService {
#Override
void foo() { .... }
Now, if I need that thing to exist as singleton, I do
enum WhateverServiceProvider implements WhateverService {
INSTANCE;
private final WhateverService impl = new WhateverServiceImpl();
#Override
void foo() { impl.foo() }
and finally, some client code can do:
WhateverService service = WhateverServiceProvider.INSTANCE;
service.foo()
(but of course, you might not want to directly assign a service object, but you could use dependency injection here)
Such architectures give you:
A clear separation between the core functionality, its implementation and the singleton concept
Guaranteed singleton semantics (if there is one thing that Java enums are really good for ... then it is that: providing fool-proof singletons!)
Full "testability" (you see - when you just use the enum, without making it available as interface ... then you have a hard time mocking that object in client code - as you can't mock enums directly).
Update - regarding thread safety:
I am not sure what exactly you mean with "singleton concept".
But lets say this: it is guaranteed that there is exactly one INSTANCE object instantiated when you use enums like that, the Java language guarantees that. But: if several threads are turning to the enum, and calling foo() in parallel ... you are still dealing with all the potential problems around such scenarios. So, yes, enum "creation" is thread-safe; but what your code is doing ... is up to you. So is then locking or whatever else makes sense.
I think you should take a look at this question:
Can a constructor in Java be private?
The Builder pattern described there could be a somewhat interesting solution:
// This is the class that will be produced by the builder
public class NameOfClassBeingCreated {
// ...
// This is the builder object
public static class Builder {
// ...
// Each builder has at least one "setter" function for choosing the
// various different configuration options. These setters are used
// to choose each of the various pieces of configuration independently.
// It is pretty typical for these setter functions to return the builder
// object, itself, so that the invocations can be chained together as in:
//
// return NameOfClassBeingCreated
// .newBuilder()
// .setOption1(option1)
// .setOption3(option3)
// .build();
//
// Note that any subset (or none) of these setters may actually be invoked
// when code uses the builer to construct the object in question.
public Builder setOption1(Option1Type option1) {
// ...
return this;
}
public Builder setOption2(Option2Type option2) {
// ...
return this;
}
// ...
public Builder setOptionN(OptionNType optionN) {
// ...
return this;
}
// ...
// Every builder must have a method that builds the object.
public NameOfClassBeingCreated build() {
// ...
}
// The Builder is typically not constructible directly
// in order to force construction through "newBuilder".
// See the documentation of "newBuilder" for an explanation.
private Builder() {}
}
// Constructs an instance of the builder object. This could
// take parameters if a subset of the parameters are required.
// This method is used instead of using "new Builder()" to make
// the interface for using this less awkward in the presence
// of method chaining. E.g., doing "(new Foo.Builder()).build()"
// is a little more awkward than "Foo.newBuilder().build()".
public static Builder newBuilder() {
return new Builder();
}
// ...
// There is typically just one constructor for the class being
// constructed that is private so that it may only be invoked
// by the Builder's "build()" function. The use of the builder
// allows for the class's actual constructor to be simplified.
private NameOfClassBeingCreated(
Option1Type option1,
Option2Type option2,
// ...
OptionNType optionN) {
// ...
}
}
Link for reference:
https://www.michaelsafyan.com/tech/design/patterns/builder
I am not sure that this is what you are looking for, but you can use Factory pattern. Create 2 factories, one will always return the same singleton, while the other one will create a new A object each time.
Factory singletonFactory = new SingetonFactory();
Factory prototypeFactory = new PrototypeFactory();
A a = singletonFactory.createA();
A b = singletonFactory.createA();
System.out.println(a == b); // true
A c = prototypeFactory.createA();
A d = prototypeFactory.createA();
System.out.println(c == d); // false
class A {
private A() {}
void doSomething() { /* do something here... */}
}
interface Factory {
A createA();
}
class SingetonFactory implements Factory {
private final A singleton = new A();
public A createA() {
return singleton;
}
}
class PrototypeFactory implements Factory {
public A createA() {
return new A();
}
}

ByteBuddy: How to implement field access interceptor?

I'am trying to make a OGM to translate object to Vertex for the OrientDB. Currently i'am using GCLib but i read that ByteBuddy could implements two critical things that if work, it will improve the OGM speed.
Could ByteBuddy implement field access control? I read the doc but it's not clear or I do not understand it.
Dinamically add default empty constructor.
The current problem is this: We do not know the class definition that will be passed as a parameter. The idea is to redefine the class and implement the empty constructor if it not have one, add a field named __BB__Dirty to set the object as dirty if an assign operation was detected and force the implementation of an interface to talk with the object.
Example:
A generic class:
public class Example {
int i = 0;
String stringField;
public Example(Strinf s) {
stringField = s;
}
public void addToI(){
i++;
}
}
Now we have an interface like this:
public interface DirtyCheck {
public boolean isDirty();
}
So, I want to force the Example class to implement the interface, the method isDirty(), a field to work on and a default contructor so the class should be translated to:
public class Example implements DirtyCheck {
int i = 0;
String stringField;
boolean __BB__dirty = false;
public Example() {
}
public Example(Strinf s) {
stringField = s;
}
public void addToI(){
i++;
}
public boolean isDirty() {
return this.__BB__dirty;
}
}
and the some magically assigner so if any field (except __BB__dirty) is modified, the __BB__dirty field is set to True;
I have tried the first part of this but I fail :(
...
ByteBuddyAgent.install();
Example ex = new ByteBuddy()
.redefine(Example.class)
.defineField("__BB__Dirty", boolean.class, Visibility.PUBLIC)
.make()
.load(Example.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
.getLoaded().newInstance();
....
ex.addToI(); // <--- this should set __BB__dirty to true since it
// assign a value to i.
But i get this error:
Exception in thread "main" java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.apply(ClassReloadingStrategy.java:297)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.load(ClassReloadingStrategy.java:173)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4350)
at Test.TestBB.<init>(TestBB.java:33)
at Test.TestBB.main(TestBB.java:23)
I'am stuck in the very first stage to solve the problem with BB.
Thanks
The Java virtual machine does not support changing the layout of classes that are already loaded when redefining a class. This is not a limitation of Byte Buddy but the VM implementation.
In order to do what you want, you should look at the AgentBuilder API which allows you to modify classes before they are loaded. Creating an agent does however require you to add it explicitly as an agent on startup (opposed to adding the library to the class path.
You can implement the interface by calling:
.implement(DirtyCheck.class).intercept(FieldAccessor.of("__dirty__");
You can also add a default constructor by simply defining one:
.defineConstructor(Visibility.PUBLIC).intercept(SuperMethodCall.INSTANCE)
The latter definition requires the super class to define a default constructor.

How to access fields from interface implementation for testing

I have an interface with a few methods
public interface Turret {
void firePrimary();
void fireSecondary();
void reloadPrimary();
.......
}
I have implementation of it which has protected fields. In my implementation of the above methods I change the values of the protected fields.
#Override
public void firePrimary() {
if(shootablePriAmmo > 0) {
shootablePriAmmo--; //Shootable ammo is a protected field inside the implementation
}else{
reloadPrimary();
}
}
Now I am trying to test the fire primary method and check whether the shootablePriAmmo value was changed or not but since this is an interface implementation I cannot access the fields with interface methods and I don't want to write methods in interface for giving access to these fields as those methods won't be used anywhere else except for testing. If I write unit tests only on the implementation classes then I have to create public getters for these fields which I don't see is the correct way of doing it. What exactly should I do to overcome this? Am I violating any OOP principle?
EDIT
Here is the constructor of the implementation
public BasicTurret(int maxPriAmmo, int maxSecAmmo, int priAmmoCap, int secAmmoCap) {
this.maxPriAmmo = maxPriAmmo;
this.maxSecAmmo = maxSecAmmo;
this.curPriAmmo = priAmmoCap;
this.curSecAmmo = secAmmoCap;
this.priAmmoCap = priAmmoCap;
this.secAmmoCap = secAmmoCap;
this.shootablePriAmmo = priAmmoCap;
this.shootableSecAmmo = secAmmoCap;
}
Introduce ammo holder interface to encapsulate ammo manipulations and simplify testing
interface AmmoHolder {
getMax();
get/setCur(); // consume or reload
getShootable();
getCap();
}
class BasicTurret(AmmoHolder primary, AmmoHolder secondary) {
this.primaryAmmo = primary;
this.secondaryAmmo = secondary;
}
You could create an object that holds the state for your values that change from these methods. Then pass a mock in through a constructor.
Unit-tests are normally created for an implementation, not for an interface, so in your unit-test you need to instantiate a class you want to test as a reference to an implementation, not an interface (in your case - BasicTurret). Also unit-tests are usually placed to the same package as the original class, so they have access to protected fields/methods if necessary.
BasicTurret turret = new BasicTurret(.., .., 5, ..);
turret.firePrimary();
assertEquals(4, turret.shootablePriAmmo);

object reference passed through constructor

Im building a relatively large object-oriented program. I have a class called AerodynamicCalculator that performs numerous calculations and distributes the results around the system. My main concern is that my constructor signature is getting larger and larger as I add mor parameters to it.
As shown below I already have nine object references being passed into this constructor, but I need a further seven. Am I correctly creating this object? My understanding is that you pass the associated object references to the constructor and assign the class'es local variable to the object references. If this is the case the only way to get my class properly initialized with all the required objects is to pass them to the constructor, which is leading to a very long signature.
public AreodynamicCalculator(AircraftConfiguration config, AileronOne aOne,
AileronTwo aTwo, ElevatorOne eOne, ElevatorTwo eTwo, Rudder r,
Rudder rr, RateGyros rG) {
// ...
}
Any advice on this approach would be very helpful, thanks in advance.
As mentioned - this may be a sign your class is doing too much, however, there is a commonly used 'solution' to this problem.
The builder pattern is often used in this situation, but it's also very useful when you have many constructors with different arguments, the builder is good because it makes the meaning of the arguments clearer, particularly when boolean literals are used.
Here is the builder pattern, the way this works is like this:
AreodynamicCalculator calc = AreodynamicCalculator.builder()
.config(theAircraftConfiguration)
.addAileron(aileronOne)
.addAileron(aileronTwo)
.addElevator(elevatorOne)
.addElevator(elevatorTwo)
.addRudder(rudderOne)
.addRudder(rudderTwo)
.build()
Internally, the builder will store all these fields, and when build() is called it will call a (now private) constructor that takes these fields:
class AreodynamicCalculator {
public static class Builder {
AircraftConfiguration config;
Aileron aileronOne;
Aileron aileronTwo;
Elevator elevatorOne;
Elevator elevatorTwo;
...
public Builder config(AircraftConfiguration config) {
this.config = config;
return this;
}
public Builder addAileron(Aileron aileron) {
if (this.aileronOne == null) {
this.aileronOne = aileron;
} else {
this.aileronTwo = aileron;
}
return this;
}
// adders / setters for other fields.
public AreodynamicCalculator build() {
return new AreodynamicCalculator(config, aileronOne, aileronTwo ... );
}
}
// this is the AircraftConfiguration constructor, it's now private because
// the way to create AircraftConfiguration objects is via the builder
//
private AircraftConfiguration config, AileronOne aOne, AileronTwo aTwo, ElevatorOne eOne, ElevatorTwo eTwo, Rudder r, Rudder rr, RateGyros rG) {
/// assign fields
}
}
Similarly to using the builder pattern, suggested in daveb's response, you can use a Dependency Injection framework like Spring.

Categories

Resources