OOP design around abstract classes - java

Lets say I have a Namespace class like follows:
abstract class Namespace {
protected prefix;
protected Map<String, String> tags;
public setTag(String tagKey, String tagValue) {
tags.put(tagKey, tagValue);
}
}
I have been told that a good design is to have separate implementations of each namespace with getters defining the information being retrieved from the tags map. ie.
class FooNamespace extends Namespace {
public String getNameTag() {
return tags.get("name");
}
}
We can have separate implementations of a namespace like BarNamespace which will have different tags stored (BarNamespace does not have a name tag for ex. and instead has an age tag). Why does the above design make more sense than simply having the consumer of a simple Namespace class request the tag they want. ie:
class Namespace {
private prefix;
private Map<String, String> tags;
public String getTag(String key) {
return tags.get(key);
}
}
The above is used like
Namespace.getTag("name");

The answer depends a lot on what you wish to achieve - but if I have to type getTag("name") a few hundred times, I'm bound to make a mistake.
getNameTag takes out some of the guess work and reduces the possibility that I'll type "name" wrong without noticing. It also reduces the amount of knowledge I need to have about the API - I know I can get the value for the name tag, but I don't need to know how that is actually implemented - and it might change between implementations.
Is it a "good design" is a matter of opinion and is dependent on how the intended class is to be used. Is "name" common enough in the application to be useful? What about "date" or "numeric" values - some helper methods there might be nice ;)
The one thing that bugs me about this is that while Bar does not have an accessor for "name", its backed by an abstract Namespace class that contains a raw Map so anyone can shove in a "name" tag by doing a Bar.putTag("name", "nameValue"); Any ideas on how to implement the "setters"?
This is also a bug-bear I have to the collections API generally.
You could create a non-mutable and mutable concepts...
public interface Namespace {
public String getTag(String key);
}
public interface MutableNamespace extends Namespace {
public void setTag(String key, String value);
}
Then you can begin to abstract those...
public abstract class AbstractNamespace implements MutableNamespace {
private prefix;
private Map<String, String> tags;
public setTag(String tagKey, String tagValue) {
tags.put(tagKey, tagValue);
}
public String getTag(String key) {
return tags.get(key);
}
}
And finally provide useful implementations for the context that it might be used in...
public interface MySuperHelpfulNamespace extends Namespace {
public String getNameTag();
}
public class DefaultMySuperHelpfulNamespace extends AbstractNamespace implements MySuperHelpfulNamespace {
public String getNameTag() {
return tags.get("name");
}
}
Then write you app to support them...
public void someMethodWhichDoesNotNeedToChangeTheValues(MySuperHelpfulNamespace namespace) {
//...
}
public void someMethodWhichDoesNeedToChangeTheValues(MutableNamespace namespace) {
//...
}
This is essentially an example of "coding to interface (not implementation)

The problem stems from..
Your attempt to reuse Namespace via inheritance for it's property: the Map.
The idea behind object orientation is to..
Tell objects to perform behaviors.
What is an Object?
Hiding internal state and requiring all interaction to be performed through an object's methods is known as data encapsulation — a fundamental principle of object-oriented programming.
When ClassA extends ClassB, the subtype ClassA should inherit the behaviors, or the public interface, of it's supertype ClassB. Your Namespace type doesn't seem to define any behaviors.
You may consider the setter or getter to be behaviors,
But don't be fooled. There is currently no reason for a developer to prefer your Namespace type over just using a Map, other than changing the interface they use from get to getTag.
getter & setter methods violate OOP. Feel free to read up on the discussion.
How should Namespace actually be used? What requirement is it fufilling? What behaviors should Namespace define?
You can answer this by analyzing how the getter is being used. To give an example, maybe you plan to append it to a StringBuilder to conjure some XML.
Imagine your requirement was..
Append an individual tag from a variety of XML tag sets to a StringBuilder that'll be used for rendering.
Instead of doing..
StringBuilder builder = ...;
Namespace namespace = ...;
builder.append(namespace.getTag("name"));
Namespace could be responsible for appending it's tags (Namespace is the owner of the Map storing the tags) to whatever is requesting it.
public final class Namespace {
private final Map<String, String> tags;
public Namespace(Map<String, String> tags) {
this.tags = tags;
}
// if you REALLY need to add tags after instantiation
public Namespace addTag(String key, String value) {
Map<String, String> tags = new HashMap<>(this.tags);
tags.put(key, value);
return new Namespace(tags);
}
// the behavior that fufills the requirement
public void appendTo(StringBuilder builder, String key) {
builder.append(tags.get(key));
}
}
Notice how Namespace has behavior (appends to a StringBuilder) rather than act as a proxy for Map.
StringBuilder builder = ...;
Namespace namespace = ...;
namespace.appendTo(builder, "name");
I'm not looking for reasons to create subtypes (not forcing it). You should only create subtypes when you must extend upon the behavior of the supertype. If BarNamespace doesn't add any functionality to Namespace, there's no need for it.
After creating Namespace to cover the functionality your post exposes, I had no need for subtypes. It seemed as if everything was elegantly handled by Namespace.
You didn't specify your requirements, but hopefully this answer will guide you towards determining them (based on how you're using the getter) and implementing them in an object oriented manner.
As #MadProgrammer pointed out:
if I have to type getTag("name") a few hundred times, I'm bound to make a mistake.
If you find yourself needing to type "name" quite often, then you may wanna include a type-safe way for performing that behavior.
In a situation like this, you could prefer composition over inheritance. Instead of having subtypes extend Namespace, you could create types that reference a Namespace to perform what you want to do.
public final class Bar {
private final Namespace namespace;
public Bar(Namespace namespace) {
this.namespace = namespace;
}
public void appendNameTo(StringBuilder builder) {
namespace.appendTo(builder, "name");
}
}
You may say "Wait! I wanna pass Bar to where a Namespace is expected!"
This would be pointless. If code relies on Namespace, there would be no type safety to be expected, even in your code. For example:
void doSomething(Namespace namespace) {
}
Unless you casted or declares appendNameTo to Namespace, you wouldn't have access to any methods defined in Bar anyways. You said subtypes may have different tags. This means if you're going for type safety, your subtypes would all have different public interfaces, hence why I didn't extend Namespace.

Related

Is it supposed that developers should implement their own XXXProperties in JavaFX?

I am reading about javafx properties and can't understand why non abstract classes we can use for creating instances of properties (for example SimpleStringProperty) have Simple word in their names. As I know Simple in implementation means basic implementation of something.
Is it supposed that developers should implement their own XXXProperty that must extend XXXPropertyBase in JavaFX?
Let's consider for example SimpleStringProperty.
java.lang.Object
javafx.beans.binding.StringExpression
javafx.beans.property.ReadOnlyStringProperty
javafx.beans.property.StringProperty
javafx.beans.property.StringPropertyBase
javafx.beans.property.SimpleStringProperty
Should we develop our own OurStringProperty that will extend StringPropertyBase?
At the same time in javadoc it is said that javafx.beans.property.StringProperty class provides a full implementation of a Property wrapping a String value. So why do we need this SimpleStringProperty? How to explain it?
Here is a sample how to add a simple Object-based property to your class using the implementations provided by JavaFX (similar classes exist for String and primitive types):
private final ObjectProperty<Foo> foo = new SimpleObjectProperty<>(this,
"foo", null);
public final Foo getFoo() {
return fooProperty().get();
}
public final void setFoo(Foo foo) {
fooProperty().set(foo);
}
public ObjectProperty<Foo> fooProperty() {
return foo;
}
Here is a sample of a read-only property implementation based on some base classes provided by JavaFX:
public class MyClass {
private final ReadOnlyBarProperty bar = new ReadOnlyBarProperty();
public final Bar getBar() {
return barProperty().get();
}
private void setBar(Bar bar) {
this.bar.set(bar);
}
public ReadOnlyObjectProperty<Bar> barProperty() {
return bar;
}
[...]
private class ReadOnlyBarProperty extends ReadOnlyObjectPropertyBase<Bar> {
private Bar bar = null;
#Override
public final Bar get() {
return bar;
}
private void set(Bar newValue) {
if (!Objects.equals(bar, newValue)) {
bar = newValue;
fireValueChangedEvent();
}
}
#Override
public Object getBean() {
return MyClass.this;
}
#Override
public String getName() {
return "bar";
}
}
}
Then there are some rare cases where you want to provide your own property implementation. E.g. I've written a SimpleEventHandlerProperty in Drombler Commons.
I hope these samples cleared things up a bit.
It depends.
There is a fairly common pattern in the standard JavaFX libraries of creating local or anonymous classes that extend one of the "base" classes (ReadOnlyXXXPropertyBase or XXXPropertyBase). In my experience, this is done usually for one of two reasons:
It's a read-only property whose value is managed from outside the property.
Something must happen internally when the property is invalidated.
To see an example of the first case take a look at the source code of ListPropertyBase. This property class has two properties of its own, empty and size, inherited from ListExpression. These properties, as expected, reflect the empty and size states of the contained ObservableList. The way these properties are implemented are as local classes but their values are managed by the ObservableList itself. The ListPropertyBase class simply has them fire change events when appropriate.
For the second case, the local or anonymous class will override the protected invalidated method provided by most (all?) of the XXXPropertyBase classes. This method is called when the property is invalidated. It allows one to react without the overhead of a listener. You can see this in action by looking at the source code of ButtonBase. For example, the onAction property:
public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() {
#Override protected void invalidated() {
setEventHandler(ActionEvent.ACTION, get());
}
#Override
public Object getBean() {
return ButtonBase.this;
}
#Override
public String getName() {
return "onAction";
}
};
When the property is invalidated, the invalidated method registers/unregisters the EventHandler from the Node.
With all that said, if you don't need to add customized behavior stick to using ReadOnlyXXXWrapper for read-only properties and SimpleXXXProperty for read-write properties.
Simple?
Why do the concrete implementations have Simple in their name? Why not just have XXXProperty be the concrete implementation?
I can't give a definitive answer, as I wasn't involved in development, but I can offer a guess: The JavaFX developers wanted to provide multiple "extension points" that offer various degrees of "already implemented". Need full customization? Extend XXXProperty. Need some customization? Extend XXXPropertyBase. And so on.
And the SimpleXXXProperty classes needed names that didn't conflict with the XXXProperty class names. Simple fits because that's what they are—simple implementations. They do nothing but what the interfaces require.
Worth Mentioning
On an API level, virtually every JavaFX class exposes properties as either ReadOnlyXXXProperty or XXXProperty. Never is it Property<SomeObject> or SimpleXXXProperty. Basically, when it comes to properties, consider using ReadOnlyXXXProperty and XXXProperty as "programming to the interface". Just like you'd expose List instead of ArrayList.
I'd also consider that quote:
This class provides a full implementation of a Property wrapping a String value.
To be misleading. If you look at the source of StringProperty is is certainly not a "full implementation". Maybe it's trying to say its the API level class? Maybe it's trying to say it implements all the necessary interfaces? Honestly, I have no idea...

Code repetition vs readablility

I have multiple services (in Spring MVC) that are children of a global Service. So I need to know about the best practice (or your opinions) with multiple methods with this example:
//Domain classes
public class MyParentObject{}
public class MyObj extends MyParentObject{}
//Services
public class MyParentObjectServiceImpl implements MyParentObjectService{
#Override
public MyParentObject findObjectByProp(String prop, String objectType){
//myCode (not abstract class)
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl implements MyObjectService{
private myObjType = "MyObj";
#Override
public MyObj findMyObjByProp(String prop){
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
And in this approach, I use calls like this:
MyObj foo = myObjService.findMyObjByProp(prop);
So I need to know if this approach is "better" or more apropiate that calling directly the parent method with the second parameter. E.g:
MyObj foo = (MyObj)myParentObjectService.findObjectByProp(prop, "MyObj");
..and avoiding the creation of second methods, more specific. It is important to know that the children services will be created anyway, because we have lot of code that is specific of a domain objects.
I have the idea that the first approach is better, because is more readable, but I need to support that decision with some documents, blog, or opinions to discuss this designs with my colleagues.
This looks like a tagged class hierarchy. It's difficult to comment on the value of this design in general without knowing the details. However, a slightly different approach that I would recommend is to generify your base class to gain a little bit of type safety.
In particular:
public /* abstract */ class MyParentObjectServiceImpl<T extends MyParentObject>
implements MyParentObjectService{
MyParentObjectServiceImpl(Class<T> type) { this.type = type; }
private final Class<T> type; // subclasses provide this
#Override
public T findObjectByProp(String prop){
//you can use type for object specific stuff
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl<MyObj>
// You might not need this interface anymore
// if the only method defined is findMyObjByProp
/* implements MyObjectService */ {
MyObjServiceImpl() {
super(MyObj.class);
}
#Override
public /* final */ MyObj findMyObjByProp(String prop) {
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
You definitely gain in type safety (casting will only appear in the base class), you get rid of the "tags" (the strings that identify the different objects) and possibly reduce the number of classes/interfaces required to implement the whole hierarchy. I successfully used this approach several times. Note that this works best if the base class is abstract. Food for thoughts.

MOXy/JAXB "prototype pattern" - interface inheritance

I'm trying to implement a version of Gang of Four's Prototype Pattern using MOXy/JAXB 2.5.0. I want to be able to specify a list of items, some of which are "based on" others, i.e. copy their data from other instances. For reusability, I'd like to create an interface that any prototype-able object should implement, which will provide annotation for the properties necessary to support the pattern.
#XmlRootElement(name="IPrototype")
public interface IPrototype
{
/**
* Acts as a "copy constructor"
*/
#XmlAttribute(name="prototype")
#XmlIDREF
public void setPrototype(IPrototype prototype);
#XmlAttribute(name="id")
#XmlID
public void setId(String id);
public String getId();
}
An implementing object would ideally look something like this, not even having to bother with annotation of the methods implemented from the interface:
#XmlRootElement(name="Item")
public class Item implements IPrototype
{
private String m_id = null;
private String m_data = null;
public Item()
{
}
/**
* Never called
*/
#Override
public void setPrototype(IPrototype prototype)
{
m_data = ((Item)prototype).getData();
}
#Override
public void setId(String id)
{
m_id = id;
}
#Override
public String getId()
{
return m_id;
}
#XmlAttribute(name="data")
public void setData(String data)
{
m_data = data;
}
public String getData()
{
return m_data;
}
}
And the XML would look like:
<Wrapper>
<Item id="Item1" data="stuff and things" />
<Item id="Item2" prototype="Item1" />
</Wrapper>
where Wrapper is defined as:
#XmlRootElement(name="Wrapper")
public class Wrapper
{
#XmlElementRef
private ArrayList<Item> m_items = null;
}
If it worked the way I want, I would get a list with two elements, both of type Item, that contain the same data. However, MOXy doesn't seem to "see" the annotations on the interface, and I get a list with two Items that don't have their XmlID set, and setPrototype() is never called. The only solution appears to be annotating the setPrototype() and setId() methods in the Item class, but this appears to require changing setPrototype()'s argument type from IPrototype to Item so MOXy will look for the XmlID in the right class. Unfortunately, this breaks the inherited interface.
If I instead change the list type to IPrototype, hoping that would allow MOXy to see its annotations, I get the same behavior - null ID's, setPrototype() never called. This isn't really what I want anyways, I'd like to be able to constrain which subtypes may be included in a particular list.
Not sure I have correct expectations for how interface annotations are supposed to work, maybe that's the source of my error.
Any thoughts on how to get this working? Thanks in advance,
Steve
UPDATE: If I annotate the Item class, WITHOUT changing setPrototype's method signature (which I guess I can live with), I get a list with two items, with correctly set XmlID's, but setPrototype() is still not called. Seems like MOXy is looking for instances of IPrototype (impossible) with the same XmlID, not Item instances.
UPDATE 2: And, if I convert IPrototype into an abstract class, everything works perfectly. However, given Java's single inheritance model, this is too limiting for a framework object that is intended to supplement multiple inheritance hierarchies. So still stuck.
I got a somewhat acceptable version of this running by annotating Item's properties and declaring setPrototype() using generics. This is what the declaration looks like in IPrototype:
public <T> void setPrototype(T prototype);
And here's its implementation in Item:
#XmlAttribute(name="prototype")
#XmlIDREF
#Override
public <T> void setPrototype(T prototype)
{
m_data = ((Item)prototype).getData();
}
It works, but I don't particularly like having to re-annotate the subclass. I've opened a separate question about that, since it doesn't intuitively (to me) seem like that's the way interface annotations should work:
MOXy/JAXB interface annotation
You can use MOXy's external binding document to override the super class of the implementing clases (i.e. Item) from Object to the interface IPrototype. This will allow you to inherit the mappings from the interface.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum16807019">
<java-types>
<java-type name="Item" super-type="forum16807019.IPrototype"/>
</java-types>
</xml-bindings>
For a complete example see:
MOXy/JAXB interface annotation

How do Generics and Fields assist DAO Pattern in Standalone Java applications

//Interface DAO
public abstract class BaseDAO<T extends BaseDTO> {
public void update(T t) throws DBException {
Field[] fieldsToInsert = t.getClass().getDeclaredFields();
//code to update database object academic or event
}
public Integer create(T t) throws DBException {
Field[] fieldsToInsert = t.getClass().getDeclaredFields();
//code to create academic or event in database
}
}
//Concrete DAOs
public class AcademicDAO extends BaseDAO<AcademicDTO> {
//provide implementation
}
public class EventDAO extends BaseDAO<EventDTO> {
//provide implementation
}
//Transfer object
public class AcademicDTO extends BaseDTO {
String title;
String surname;
//getters and setters
}
public class BaseDTO {
protected Integer ID;
public Integer getID() {
return ID;
}
public void setID(Integer ID) {
this.ID = ID;
}
}
Hello Guys, I have a sample code on me that follows the above structure to create a small java application to manage academics and events. It is leniently following this pattern
1- You experts are familiar with this pattern more than me. I would like to understand why generics are used in this case so DAOs can extend and implement a generic base class. It would be great if one can show how generics here may be advantageous using an example.
2 - I have also witnessed the use of java Fields. Is there a link between generics and Fields?
I would like to document DAO pattern in an academic report, but I am finding difficult to understand how Generics and Reflect Field play a part here. Do they support flexibility and loose coupling?
The code you've provided is reusable set of logic to load and persist entities. Many times, in an application of non-trivial size, you'll wind up persisting many different types of objects. In this example, you can define as many objects as necessary, but only define the logic to actually save and load once. By asking the DTO what Field objects are there, it can get at the data to help construct queries for loading and saving.
Generics allow you to use this pattern while maintaining type safety. AcademicDAO can only handle AcadmeicDTO. You can't use AcademicDAO to store EventDTO. Generics allow the instance of the class to rely on a more specific type when dealing with the Field objects. If you didn't have generics, the BaseDAO would take Object, and you wouldn't be able to access any methods except those that Object provides because the JVM wouldn't know what class is provided, so it has to limit it's knowledge to that of Object. Using getClass().getDeclaredFields() bypasses that limitation because getClass() returns the actual class of the Object parameter.
Field is just a way to use reflection to access the values of the properties in each DTO. If you had to access the fields directly, with getTitle(), you couldn't reuse a generic base class to do your persistence. What would happen when you needed to access EventDTO? You would have to provide logic for that. Field allows you to skip that logic.
Edit:
To explain what I mean by accessing getID, you could do the following within BaseDAO because T is known to be a BaseDTO with a getID() method defined:
public abstract class BaseDAO<T extends BaseDTO> {
public boolean update(T t) throws DBException {
Integer id = t.getID();
Field[] fields = t.getClass().getDeclaredFields();
// Assuming you have a db object to execute queries using bind variables:
boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
return success;
}
}
If you had this instead (in a non-generic class):
public boolean update(Object o) throws DBException {
// This line doesn't work, since Object doesn't have a getID() method.
Integer id = t.getID();
Field[] fields = o.getClass().getDeclaredFields();
boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
return success;
}
You'd have to look through those Field objects, or ask for the ID field and assume it existed.
For question 1. The use of generics allows the same implementations of update and create to be used regardless of the type of the DTO. Consider if you didn't use generics. Then the best you could do for the parameter type of update would be BaseDTO, but then you could call
academicDAO.update( eventDTO )
which doesn't make sense. With the code as you have it, this would be a type error. So the main advantage is: better type checking.
For question 2. The use of Fields allows a single implementation of update and create to work on DTO object of various concrete types.

Java - Alternatives to forcing subclass to have a static method

I often find I want to do something like this:
class Foo{
public static abstract String getParam();
}
To force a subclasses of Foo to return a parameter.
I know you can't do it and I know why you can't do it but the common alternative of:
class Foo{
public abstract String getParam();
}
Is unsatisfactory because it requires you to have an instance which is not helpful if you just want to know the value of the parameter and instantiating the class is expensive.
I'd be very interested to know of how people get around this without getting into using the "Constant Interface" anti pattern.
EDIT: I'll add some more detail about my specific problem, but this is just the current time when I've wanted to do something like this there are several others from the past.
My subclasses are all data processors and the superclass defines the common code between them which allows them to get the data, parse it and put it where it needs to go.
The processors each require certain parameters which are held in an SQL database. Each processor should be able to provide a list of parameters that it requires and the default values so the configuration database can be validated or initialised to defaults by checking the required parameters for each processor type.
Having it performed in the constructor of the processor is not acceptable because it only needs to be done once per class not once per object instance and should be done at system startup when an instance of each type of class may not yet be needed.
The best you can do here in a static context is something like one of the following:
a. Have a method you specifically look for, but is not part of any contract (and therefore you can't enforce anyone to implement) and look for that at runtime:
public static String getParam() { ... };
try {
Method m = clazz.getDeclaredMethod("getParam");
String param = (String) m.invoke(null);
}
catch (NoSuchMethodException e) {
// handle this error
}
b. Use an annotation, which suffers from the same issue in that you can't force people to put it on their classes.
#Target({TYPE})
#Retention(RUNTIME)
public #interface Param {
String value() default "";
}
#Param("foo")
public class MyClass { ... }
public static String getParam(Class<?> clazz) {
if (clazz.isAnnotationPresent(Param.class)) {
return clazz.getAnnotation(Param.class).value();
}
else {
// what to do if there is no annotation
}
}
I agree - I feel that this is a limitation of Java. Sure, they have made their case about the advantages of not allowing inherited static methods, so I get it, but the fact is I have run into cases where this would be useful. Consider this case:
I have a parent Condition class, and for each of its sub-classes, I want a getName() method that states the class' name. The name of the sub-class will not be the Java's class name, but will be some lower-case text string used for JSON purposes on a web front end. The getName() method will not change per instance, so it is safe to make it static. However, some of the sub-classes of the Condition class will not be allowed to have no-argument constructors - some of them I will need to require that some parameters are defined at instantiation.
I use the Reflections library to get all classes in a package at runtime. Now, I want a list of all the names of each Condition class that is in this package, so I can return it to a web front end for JavaScript parsing. I would go through the effort of just instantiating each class, but as I said, they do not all have no-argument constructors. I have designed the constructors of the sub-classes to throw an IllegalArgumentException if some of the parameters are not correctly defined, so I cannot merely pass in null arguments. This is why I want the getName() method to be static, but required for all sub-classes.
My current workaround is to do the following: In the Condition class (which is abstract), I have defined a method:
public String getName () {
throw new IllegalArugmentException ("Child class did not declare an overridden getName() method using a static getConditionName() method. This must be done in order for the class to be registerred with Condition.getAllConditions()");
}
So in each sub-class, I simply define:
#Override
public String getName () {
return getConditionName ();
}
And then I define a static getConditionName() method for each. This is not quite "forcing" each sub-class to do so, but I do it in a way where if getName() is ever inadvertently called, the programmer is instructed how to fix the problem.
It seems to me you want to solve the wrong problem with the wrong tool. If all subclasses define (can't really say inherit) your static method, you will still be unable to call it painlessly (To call the static method on a class not known at compile time would be via reflection or byte code manipulation).
And if the idea is to have a set of behaviors, why not just use instances that all implement the same interface? An instance with no specific state is cheap in terms of memory and construction time, and if there is no state you can always share one instance (flyweight pattern) for all callers.
If you just need to couple metadata with classes, you can build/use any metadata facility you like, the most basic (by hand) implementation is to use a Map where the class object is the key. If that suits your problem depends on your problem, which you don't really describe in detail.
EDIT: (Structural) Metadata would associate data with classes (thats only one flavor, but probably the more common one). Annotations can be used as very simple metadata facility (annotate the class with a parameter). There are countless other ways (and goals to achieve) to do it, on the complex side are frameworks that provide basically every bit of information designed into an UML model for access at runtime.
But what you describe (processors and parameters in database) is what I christened "set of behaviors". And the argument "parameters need to be loaded once per class" is moot, it completely ignores the idioms that can be used to solve this without needing anything 'static'. Namely, the flyweight pattern (for having only once instance) and lazy initialization (for doing work only once). Combine with factory as needed.
I'm having the same problem over and over again and it's hard for me to understand why Java 8 preferred to implement lambda instead of that.
Anyway, if your subclasses only implement retrieving a few parameters and doing rather simple tasks, you can use enumerations as they are very powerful in Java: you can basically consider it a fixed set of instances of an interface. They can have members, methods, etc. They just can't be instanciated (as they are "pre-instanciated").
public enum Processor {
PROC_IMAGE {
#Override
public String getParam() {
return "image";
}
},
PROC_TEXT {
#Override
public String getParam() {
return "text";
}
}
;
public abstract String getParam();
public boolean doProcessing() {
System.out.println(getParam());
}
}
The nice thing is that you can get all "instances" by calling Processor.values():
for (Processor p : Processorvalues()) {
System.out.println(String.format("Param %s: %s", p.name(), p.getParam()));
p.doProcessing();
}
If the processing is more complex, you can do it in other classes that are instanciated in the enum methods:
#Override
public String getParam() {
return new LookForParam("text").getParam();
}
You can then enrich the enumeration with any new processor you can think of.
The down side is that you can't use it if other people want to create new processors, as it means modifying the source file.
You can use the factory pattern to allow the system to create 'data' instances first, and create 'functional' instances later. The 'data' instances will contain the 'mandatory' getters that you wanted to have static. The 'functional' instances do complex parameter validation and/or expensive construction. Of course the parameter setter in the factory can also so preliminary validation.
public abstract class Processor { /*...*/ }
public interface ProcessorFactory {
String getName(); // The mandatory getter in this example
void setParameter(String parameter, String value);
/** #throws IllegalStateException when parameter validation fails */
Processor construct();
}
public class ProcessorA implements ProcessorFactory {
#Override
public String getName() { return "processor-a"; }
#Override
public void setParameter(String parameter, String value) {
Objects.requireNonNull(parameter, "parameter");
Objects.requireNonNull(value, "value");
switch (parameter) {
case "source": setSource(value); break;
/*...*/
default: throw new IllegalArgumentException("Unknown parameter: " + parameter);
}
}
private void setSource(String value) { /*...*/ }
#Override
public Processor construct() {
return new ProcessorAImpl();
}
// Doesn't have to be an inner class. It's up to you.
private class ProcessorAImpl extends Processor { /*...*/ }
}

Categories