What is the way to create API Library in Java - java

I am creating an API of a list of checking functions. There is an object passed in as an argument to be checked.
The object is like below:
public class People{
private String name;
private String address;
private int age;
private String job;
public getter() ...
public setter() ...
}
I create a class including a list of checking function to make sure the provided information is valid or not. For example:
public class checkingFunctions {
public static boolean checkName(People ppl){
perform the name checking function;
}
public static boolean checkAge(People ppl){
perform the age checking function;
}
}
I know the above way works as an API so that other people can call checkingFunctions.checkName(ppl). But is this the correct way to build the API that will be exposed to others as jar file ? I was thinking to create an interface of checkingFunctions like below:
public interface ICheckingFunctions {
boolean checkName(People);
boolean checkAge(People);
}
And let the checkingFunctions class to implement it, like
public class checkingFunctions implements ICheckingFunctions {
}
BUt it won't compile because the checkName and checkAge can not be declared as static if it is overriding a superclass method.
Or should I just use the interface and let it implement the interface, but remove the static from all checking method. So, if others want to use my API, they just instantiate the interface, and use instance.checkName() to call method ? is that a good way ?
I am wondering whether there there exists an industry standard or design pattern standard to create such an interface so that others can call it.
Thanks a lot.

How to design such an API very much depends on how your API is intended to be used.
If it for example turns out, that your People class is best implemented as a final class, and you want to make sure, that it is always checked in the same consistent way, then providing a number of public static check... methods is certainly a reasonable way to go.
If on the other hand you do not know in advance how your People class should be checked, then I'd consider providing an ICheckingFunctions interface that declares the necessary check... methods. But if you go this route, you will perhaps also need to provide a way for the user to change the actually used implementation of ICheckingFunctions.
You should also consider, that while using an interface is certainly much more flexible and extensible, it is also more work to maintain and it could also provide a possible security risk - e.g. if you allow users to change the used ICheckingFunction, then you no longer have control of how your People class is checked.
One possible way to implement such an API using an interface is allowing users to register/unregister the used ICheckingFunction in your class. A very naive implementation could look like this:
public final class CheckingFunctions {
private static ICheckingFunctions checkFunction;
public static void registerCheckFunction(ICheckingFunctions checkFunction) {
CheckingFunctions.checkFunction = checkFunction;
}
public static boolean checkName(People ppl){
return checkFunction.checkName(ppl);
}
public static boolean checkAge(People ppl){
return checkFunction.checkAge(ppl);
}
}
This is of course just a minimal example. In an actual API you would have to decide quite a lot of additional details. For example:
Is there only ever a single ICheckingFunctions instance available? If there may be more registered ICheckingFunctions - how do you choose which of these functions are used?
Who is allowed to register/unregister an ICheckingFunctions instance?
May the ICheckingFunctions be called from different threads?
etc.
You must also consider in which environment your API is going to be used. If you for example want to support usage of your API in an OSGI environment, then you could e.g. supply your ICheckingFunctions as an OSGI service.
Last but not least I would consider the following: May your users subclass the People class? If yes, then it would perhaps be a good idea to make the ICheckingFunctions interface generic, and allow registrations of implementations for different classes. Here again a very naive example of this approach:
public final class CheckingFunctions {
public interface ICheckingFunctions<T extends People> {
boolean checkName(T p);
boolean checkAge(T p);
}
private static Map<Class<?>,ICheckingFunctions<?>> checkFunctions = new ConcurrentHashMap<>();
public static <T extends People> void registerCheckFunction(ICheckingFunctions<T> checkFunction, Class<T> c) {
checkFunctions.put(c, checkFunction);
}
private static <T extends People> ICheckingFunctions<T> getRegisteredCheckFunction(Class<T> c){
ICheckingFunctions<T> checkFunction = (ICheckingFunctions<T>) checkFunctions.get(c);
if (checkFunction == null) {
// provide some reasonable default?
throw new IllegalStateException();
}
return checkFunction;
}
public static <T extends People> boolean checkName(T ppl, Class<T> c){
return getRegisteredCheckFunction(c).checkName(ppl);
}
public static <T extends People> boolean checkAge(T ppl, Class<T> c){
return getRegisteredCheckFunction(c).checkAge(ppl);
}
}

Related

Java Hibernate: What would be the better design to get rid of casting

I use Hibernate for persistence.
Suppose I have an entity which contains information about the document and the necessary information for producing it (either printing or sending by email). Just like this:
The problem here is that DocumentInformation holds reference to abstract class DocumentProductionConfiguration not to the subclasses DocumentPrintConfiguration or DocumentEmailConfiguration.
So when I actually need to get appropriate configuration I have two choices: either use instanceof + casting or use visitor pattern to trick Java so that it would actually understand in the runtime which configuration it is dealing with.
Using casting:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
if(documentInformation.getDocumentProductionConfiguration() instanceOf DocumentPrintConfiguration){
DocumentPrintConfiguration printConfig = (DocumentPrintConfiguration) documentInformation.getDocumentProductionConfiguration();
XMLMessageConfig xmlConfig = handlePrintConfig(printConfig);
}
}
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
}
Using visitor pattern:
I need to add a new interface for XmlBuilder to implement
public interface XmlBuilderVisitor<T> {
T handlePrintConfig(DocumentPrintConfiguration printConfig);
}
public class XmlBuilder implements XmlBuilderVisitor<XMLMessageConfig> {
#Override
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlMessageConfig = documentInformation.getDocumentProductionConfiguration().buildConfiguration(this);
}
}
public abstract class DocumentProductionConfiguration{
public abstract <T> T buildConfiguration(XmlBuilderVisitor<T> visitor);
}
public class DocumentPrintConfiguration extends DocumentProductionConfiguration{
public <T> T buildConfiguration(XmlBuilderVisitor<T> visitor){
return visitor.handlePrintConfig(this);
}
}
Both of these solutions are kinda meh... The first one because it violates open-closed principle (I will need to always maintain these ifs...).
The second one in this sense is better: once you add new configuration, compiler will guide you through the process: first, you will need to implement appropriate method in the configuration itself, then in all the visitor classes. On the other hand, it is pretty awkward that I am basically passing service to the entity...
So I feel like I am treating symptoms rather than the problem. Maybe the design itself needs some changes? But I am not sure how it could be improved...
I would reccomend pushing the "handle" functionality into the DocumentProductionConfiguration and subclasses. So that the DocumentPrintConfiguration would contain a handle function that builds and returns a XMLMessageConfig. Then your XmlBuilder becomes:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
}
}

Should constant details be part of the abstraction or the implementation?

I have a SaveSettings network operation in my application.
I am using an adapter so that I can be free to plug in another networking library in the future and not change any of my code.
public interface SaveSettingsOnServerAdapter {
void saveSettings(User user, OnSaveSettingsOnServerListener listener);
}
public class SaveSettingsOnServerAdapterImpl implements SaveSettingsOnServerAdapter {
private static final String API_USER_SESSION_HEADER = "Cookie";
private static final String API_SAVE_SETTINGS_PATH = "user/{user_id}/update";
private static final String API_SAVE_SETTINGS_USER_ID_PATH_PARAMETER = "user_id";
private static final String API_SAVE_SETTINGS_SYNC_WITH_CALENDAR_PARAMETER = "sync_with_calendar";
private static final String API_SAVE_SETTINGS_USE_MOBILE_NETWORK_PARAMETER = "use_mobile_network";
#Override
void saveSettings(User user, OnSaveSettingsOnServerListener listener) {
// Some implementation here, in my case - RETROFIT
}
}
My gut feeling tells me that those details outlined in the constants defined in the Implementation class are independent of whatever networking library I choose to use for the networking, so they should be part of the abstraction, right?
If so, should I declare SaveSettingsOnNetworkAdapter abstract and insert them there? And then SaveSettingsOnNetworkAdapterImpl extend it instead of implement it? Is it a problem to extend an abstract class instead of implementing an interface when employing the Adapter pattern?
Downgrading an interface to an abstract class isn't unproblematic. You force all future implementations to extend that class and only that class, whereas currently you can attach the interface to almost anything.
Plus, the parameters may be constant (as far as you can tell now) but is it really the responsibility of a SaveSettingsOnServerAdapter to keep & define them?
They are required in there for sure. But requirements can be provided by other places as well. The most versatile / abstract solution to that is to define another interface that provides the values and to add the dependency to that interface to the constructor of every SaveSettingsOnServerAdapter implementation.
If you don't like to repeat that constructor, that would be a good place to make an abstract class that implements SaveSettingsOnServerAdapterImpl and covers the common code to deal with the external interface.
But it's up to you. Whether you want more encapsulation and to which degree you want that depends on what you're working on. In a tiny tool that isn't going to change is pointless since abstractions aim to make change easy. And more abstraction also means more code and more code means more places that can break.
public interface ServerConfiguration {
String getHeader();
String getPath();
...
}
public enum DefaultServerConfiguration implements ServerConfiguration {
INSTANCE;
private static final String API_USER_SESSION_HEADER = "Cookie";
private static final String API_SAVE_SETTINGS_PATH = "user/{user_id}/update";
...
#Override
public String getHeader() {
return API_SAVE_SETTINGS_PATH;
}
#Override
public String getPath() {
return API_SAVE_SETTINGS_PATH;
}
...
}
public class SaveSettingsOnServerAdapterImpl implements SaveSettingsOnServerAdapter {
private final ServerConfiguration config;
public SaveSettingsOnServerAdapterImpl(ServerConfiguration config) {
this.config = config;
}
#Override
void saveSettings(User user, OnSaveSettingsOnServerListener listener) {
new Request().withHeader(config.getHeader());
}
}
public class UserOfAllThis {
new SaveSettingsOnServerAdapterImpl(DefaultServerConfiguration.INSTANCE);
}
The idea of abstraction is to make your code more generic. This should hide implementation as much as possible. Adding constants to the abstract layer will reveal some implementation details. The best way will probably be to add the constants to the implementation class or create a new class with these constants.

Java Inheritance - Building a BaseView for the MVP pattern

We are trying to implement the MVP pattern. Because it requires quite a lot of code just to have a functioning view, we try to use inheritance as much as possible. As I am pretty new to Java, I don't know exactly if I'm doing it right:
So, I started with a very simple Interface which all the views will implement (and the `getName`` method will be used for breadcrumb Feature):
public interface IView {
public String getName();
}
On top of that, I built a BaseView which will be used for most views:
public interface IBaseView extends IView {
public void addListener(IBaseViewListener l);
interface IBaseViewListener {
void viewEntered(Long id);
}
}
And the implementation
public class BaseView extends CustomComponent implements View, IBaseView{
private String name = "";
private List<IBaseViewListener> listeners;
public BaseView(String name) {
this.name = name;
listeners = new ArrayList<IBaseViewListener>();
buildLayout();
}
#Override
public void addListener(IBaseViewListener l) {
listeners.add(l);
}
protected void buildLayout() {
this.setId("base_view");
// initialize layout....
}
#Override
public void enter(ViewChangeEvent event) {
for (IBaseViewListener l : listeners) {
l.viewEntered(id);
}
}
#Override
public String getName() {
return name;
}
}
And last we have a ScaffoldingView which will be used for some views (mainly for mocking):
public interface IScaffoldingView extends IBaseView{
public void showTable(AbstractComponent t);
interface IScaffoldingViewListener extends IBaseViewListener {
void itemSelected(DataBaseObject selectedObject);
}
}
And the implementation:
public class ScaffoldingView extends BaseView implements IScaffoldingView{
private AbstractComponent table = null;
public ScaffoldingView(String name) {
super(name);
}
#Override
protected void buildLayout() {
// here is a lot more code...
}
public void showTable(AbstractComponent t) {
// here is a lot of code...
}
}
First of all:
- Does that approach make any sense? especially the access modifiers. I'm totally weak when it Comes to polymorphism :(
I am very unsure about the handling of the EventListeners. For example: In the constructor of the BaseView, I am implementing the addListener function.
Now, in the ScaffoldingView's, there will be a specialized IScaffoldingViewListener. Will the super class (BaseView) addListener() method be able to handle These IScaffoldingViewListeners?
edit: Sorry, I forgot to mention that View and CustomComponent are some classes of a 3rd Party Framework (Vaadin) which we use and which offer the enter Event in which we call the eventListeners (Presenter).
First, declaring an interface inside another interface is not quite clean, obscures the code quite a bit.
Second, about BaseView which extends CustomComponent, and implements IView and IBaseView, first a small detail, if it implements IBaseView, you do not need to implement IView, as IBaseView already extends IView, but the bigger issue i see is:
If you have a somewhere in some class, a method with an IBaseView as a parameter, but inside that function you expect to be able to use the overrided methods from CustomComponent, you won't be able to, you'll only have the methods declared on IBaseView.
If you wanted to use the CustomComponent methods, you'd had to do a cast inside that method, but that is not clean and a source of bugs, because if in the future, you add more classes that implement IBaseView but do not extend CustomComponent, that function will throw exceptions complaining about casting.
Also, about the ScaffoldingView, if you are going to use it only for mocking purposes in tests and you are extending the IBaseView behaviour, with more methods, if you test a method that has an IBaseView as parameter, you have the same exact situation as before, the method you are testing will not be aware of the IScaffoldingView declared methods, and then it won't use them, and your tests can't be trusted.
P.D.: if you are interested in learning about abstractions and inheritance design, i'd recomend you to check S.O.L.I.D. principles, there's a lot of literature in the web about those.
Edit: Response to your comment
First you need to ask yourself without thinking about internal details or implementations or testing or anything else, what are the behaviour my Views have? are they all behaving the same way? do i have different types of views or not really? Once you answer these questions and got an idea of what is going on, you'll have what it will need to design the interface hierarchy, and thats what is going to be exposed to the rest of the system.
You can (optionally) have abstract classes that derive from those interfaces, where you can provide some initialization, defaults, but, do not go further in offering more functionality than the interface offers, you can have some extra methods, but only for internal use.
And then you can derive the actual implementation of the views from the interface or the intermediate abstract classes if you have defined any.
Just think of this as a black box, in which the only thing you can see are the input and output interfaces, everything else that is going inside that box, the rest of the system doesn't and shouldn't need to know about.
Can't really give you specific solution because i'm not aware of the needs of your application.

Simulate static abstract and dynamic linking on static method call in Java

Introduction
As a disclaimer, I'v read Why can't static methods be abstract in Java and, even if I respectfully disagree with the accepted answer about a "logical contradiction", I don't want any answer about the usefulness of static abstract just an answer to my question ;)
I have a class hierarchy representing some tables from a database. Each class inherits the Entity class which contains a lot of utility methods for accessing the database, creating queries, escaping characters, etc.
Each instance of a class is a row from the database.
The problem
Now, in order to factorize as much code as possible, I want to add information about related columns and table name for each class. These informations must be accessible without a class instance and will be used in Entity to build queries among other things.
The obvious way to store these data are static fields returned by static methods in each class. Problem is you can't force the class to implement these static methods and you can't do dynamic linking on static methods call in Java.
My Solutions
Use a HashMap, or any similar data structure, to hold the informations. Problem : if informations are missing error will be at runtime not compile time.
Use a parallel class hierarchy for the utility function where each corresponding class can be instantiated and dynamic linking used. Problem : code heavy, runtime error if the class don't exist
The question
How will you cope with the absence of abstract static and dynamic linking on abstract method ?
In a perfect world, the given solution should generate a compile error if the informations for a class are missing and data should be easily accessible from withing the Entity class.
The answer doesn't need to be in Java, C# is also ok and any insight on how to do this without some specific code in any language will be welcomed.
Just to be clear, I don't have any requirement at all besides simplicity. Nothing have to be static. I only want to retrieve table and columns name from Entity to build a query.
Some code
class Entity {
public static function afunction(Class clazz) { // this parameter is an option
// here I need to have access to table name of any children of Entity
}
}
class A extends Entity {
static String table = "a";
}
class B extends Entity {
static String table = "b";
}
You should use the Java annotation coupled with the javac annotation processor, as it's the most efficient solution. It's however a bit more complicated than the usual annotation paradigm.
This link shows you how you can implement an annotation processor that will be used at the compile time.
If I reuse your example, I'd go this way:
#Target(ElementType.TYPE)
#Retention(RetentionType.SOURCE)
#interface MetaData {
String table();
}
abstract class Entity {}
#MetaData(table="a")
class A extends Entity {}
#MetaData(table="b")
class B extends Entity {}
class EntityGetter {
public <E extends Entity> E getEntity(Class<E> type) {
MetaData metaData = type.getAnnotation(MetaData.class);
if (metaData == null) {
throw new Error("Should have been compiled with the preprocessor.");
// Yes, do throw an Error. It's a compile-time error, not a simple exceptional condition.
}
String table = metaData.table();
// do whatever you need.
}
}
In your annotation processing, you then should check whether the annotation is set, whether the values are correct, and make the compilation fail.
The complete documentation is available in the documentation for the package javax.annotation.processing.
Also, a few tutorials are available on the Internet if you search for "java annotation processing".
I will not go deeper in the subject as I never used the technology myself before.
I have run into the same problems as you, and am using the following approach now. Store Metadata about columns as annotations and parse them at runtime. Store this information in a map. If you really want compile time errors to appear, most IDEs (Eclipse e.g.) support custom builder types, that can validate the classes during build time.
You could also use the compile time annotation processing tool which comes with java, which can also be integrated into the IDE builds. Read into it and give it a try.
In Java the most similar approach to "static classes" are the static enums.
The enum elements are handed as static constants, so they can be accesed from any static context.
The enum can define one or more private constructors, accepting some intialization parameters (as it could be a table name, a set of columns, etc).
The enum class can define abstract methods, which must be implemented by the concrete elements, in order to compile.
public enum EntityMetadata {
TABLE_A("TableA", new String[]{"ID", "DESC"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("I'm positively TableA Metadata");
}
},
TABLE_B("TableB", new String[]{"ID", "AMOUNT", "CURRENCY"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("FOO BAR message, or whatever");
}
};
private String tableName;
private String[] columnNames;
private EntityMetadata(String aTableName, String[] someColumnNames) {
tableName=aTableName;
columnNames=someColumnNames;
}
public String getTableName() {
return tableName;
}
public String[] getColumnNames() {
return columnNames;
}
public abstract void doSomethingWeirdAndExclusive();
}
Then to access a concrete entity metadata this would be enough:
EntityMetadata.TABLE_B.doSomethingWeirdAndExclusive();
You could also reference them from an Entity implemetation, forcing each to refer an EntityMetadata element:
abstract class Entity {
public abstract EntityMetadata getMetadata();
}
class A extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_A;
}
}
class B extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_B;
}
}
IMO, this approach will be fast and light-weight.
The dark side of it is that if your enum type needs to be really complex, with lot of different params, or a few different complex overriden methods, the source code for the enum can become a little messy.
Mi idea, is to skip the tables stuff, and relate to the "There are not abstract static methods". Use "pseudo-abstract-static" methods.
First define an exception that will ocurr when an abstract static method is executed:
public class StaticAbstractCallException extends Exception {
StaticAbstractCallException (String strMessage){
super(strMessage);
}
public String toString(){
return "StaticAbstractCallException";
}
} // class
An "abstract" method means it will be overriden in subclasses, so you may want to define a base class, with static methods that are suppouse to be "abstract".
abstract class MyDynamicDevice {
public static void start() {
throw new StaticAbstractCallException("MyDynamicDevice.start()");
}
public static void doSomething() {
throw new StaticAbstractCallException("MyDynamicDevice.doSomething()");
}
public static void finish() {
throw new StaticAbstractCallException("MyDynamicDevice.finish()");
}
// other "abstract" static methods
} // class
...
And finally, define the subclasses that override the "pseudo-abstract" methods.
class myPrinterBrandDevice extends MyDynamicDevice {
public static void start() {
// override MyStaticLibrary.start()
}
/*
// ops, we forgot to override this method !!!
public static void doSomething() {
// ...
}
*/
public static void finish() {
// override MyStaticLibrary.finish()
}
// other abstract static methods
} // class
When the static myStringLibrary doSomething is called, an exception will be generated.
I do know of a solution providing all you want, but it's a huge hack I wouldn't want in my own code nowadays:
If Entity may be abstract, simply add your methods providing the meta data to that base class and declare them abstract.
Otherwise create an interface, with methods providing all your data like this
public interface EntityMetaData{
public String getTableName();
...
}
All subclasses of Entity would have to implement this interface though.
Now your problem is to call these methods from your static utility method, since you don't have an instance there. So you need to create an instance. Using Class.newInstance() is not feasable, since you'd need a nullary constructor, and there might be expensive initialization or initialization with side-effects happening in the constructor, you don't want to trigger.
The hack I propose is to use Objenesis to instantiate your Class. This library allows instatiating any class, without calling the constructor. There's no need for a nullary constructor either. They do this with some huge hacks internally, which are adapted for all major JVMs.
So your code would look like this:
public static function afunction(Class clazz) {
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator instantiator = objenesis.getInstantiatorOf(clazz);
Entity entity = (Entity)instantiator.newInstance();
// use it
String tableName = entity.getTableName();
...
}
Obviously you should cache your instances using a Map<Class,Entity>, which reduces the runtime cost to practically nothing (a single lookup in your caching map).
I am using Objenesis in one project of my own, where it enabled me to create a beautiful, fluent API. That was such a big win for me, that I put up with this hack. So I can tell you, that it really works. I used my library in many environments with many different JVM versions.
But this is not good design! I advise against using such a hack, even if it works for now, it might stop in the next JVM. And then you'll have to pray for an update of Objenesis...
If I were you, I'd rethink my design leading to the whole requirement. Or give up compile time checking and use annotations.
Your requirement to have static method doesn't leave much space for clean solution. One of the possible ways is to mix static and dynamic, and lose some CPU for a price of saving on RAM:
class Entity {
private static final ConcurrentMap<Class, EntityMetadata> metadataMap = new ...;
Entity(EntityMetadata entityMetadata) {
metadataMap.putIfAbsent(getClass(), entityMetadata);
}
public static EntityMetadata getMetadata(Class clazz) {
return metadataMap.get(clazz);
}
}
The way I would like more would be to waste a reference but have it dynamic:
class Entity {
protected final EntityMetadata entityMetadata;
public Entity(EntityMetadata entityMetadata) {
this.entityMetadata=entityMetadata;
}
}
class A extends Entity {
static {
MetadataFactory.setMetadataFor(A.class, ...);
}
public A() {
super(MetadataFactory.getMetadataFor(A.class));
}
}
class MetadataFactory {
public static EntityMetadata getMetadataFor(Class clazz) {
return ...;
}
public static void setMetadataFor(Class clazz, EntityMetadata metadata) {
...;
}
}
You could get even get rid of EntityMetadata in Entity completely and leave it factory only. Yes, it would not force to provide it for each class in compile-time, but you can easily enforce that in the runtime. Compile-time errors are great but they aren't holy cows after all as you'd always get an error immediately if a class hasn't provided a relevant metadata part.
I would have abstracted away all meta data for the entities (table names, column names) to a service not known by the entities them selfs. Would be much cleaner than having that information inside the entities
MetaData md = metadataProvider.GetMetaData<T>();
String tableName = md.getTableName();
First, let me tell you I agree with you I would like to have a way to enforce static method to be present in classes.
As a solution you can "extend" compile time by using a custom ANT task that checks for the presence of such methods, and get error in compilation time. Of course it won't help you inside you IDE, but you can use a customizable static code analyzer like PMD and create a custom rule to check for the same thing.
And there you java compile (well, almost compile) and edit time error checking.
The dynamic linking emulation...well, this is harder. I'm not sure I understand what you mean. Can you write an example of what you expect to happen?

Design pattern to handle settings in subclasses?

I have a small hierarchy of classes that all implement a common interface.
Each of the concrete class needs to receive a settings structure containing for instance only public fields. The problem is that the setting structure
has a part common to all classes
has another part that vary from one concrete class to another
I was wondering if you had in your mind any elegant design to handle this. I would like to build something like:
BaseFunc doer = new ConcreteImplementation1();
with ConcreteImplementation1 implements BaseFunc. And have something like
doer.setSettings(settings)
but have the ''settings'' object having a concrete implementation that would be suitable to ConcreteImplementation1.
How would you do that?
This may be a named design pattern, if it is, I don't know the name.
Declare an abstract class that implements the desired interface. The abstract class constructor should take an instance of your settings object from which it will extract the global settings. Derive one or more classes from the abstract class. The derived class constructor should take an instance of your settings object, pass it to the parent class constructor, then extract any local settings.
Below is an example:
class AbstractThing implements DesiredInterface
{
private String globalSettingValue1;
private String globalSettingValue2;
protected AbstractThing(Settings settings)
{
globalSettingValue1 = settings.getGlobalSettingsValue1();
globalSettingValue2 = settings.getGlobalSettingsValue2();
}
protected String getGlobalSettingValue1()
{
return globalSettingValue1;
}
protected String getGlobalSettingValue2()
{
return globalSettingValue2;
}
}
class DerivedThing extends AbstractThing
{
private String derivedThingSettingValue1;
private String derivedThingSettingValue2;
public DerivedThing(Settings settings)
{
super(settings);
derivedThingSettingValue1 = settings.getDerivedThingSettingsValue1();
derivedThingSettingValue2 = settings.getDerivedThingSettingsValue2();
}
}
Have a matching hierarchy of settings objects, use Factory to create the settings that match a specific class.
Sounds like you need a pretty standard Visitor pattern.
To put it simple, suppose, that all your properties are stored as key-value pairs in maps. And you have 3 classes in your hierarchy: A, B, C. They all implement some common interface CI.
Then you need to create a property holder like this:
public class PropertyHolder {
public Map<String, String> getCommonProperties () { ... }
public Map<String, String> getSpecialPropertiesFor (CI a) { return EMPTY_MAP; }
public Map<String, String> getSpecialPropertiesFor (A a) { ... }
public Map<String, String> getSpecialPropertiesFor (B b) { ... }
...
}
All your classes should implement 1 method getSpecialProperties which is declared in the interface CI. The implementation as simple as:
public Map<String, String> getSpecialProperties (PropertyHolder holder) {
return holder.getSpecialPropertiesFor (this);
}
I went down this route once. It worked, but after decided it wasn't worth it.
You can define a base class MyBean or something, and it has its own mergeSettings method. Every class you want to use this framework can extend MyBean, and provide its own implementation for mergeSettings which calls the superclasses mergeSettings. That way the common fields can be on the super class. If you want to get really fancy you can define and interface and abstract class to really make it pretty. And while your at it, maybe you could use reflection. anyway, mergeSettings would take a Map where the key is the property name. Each class would have its constants to related to the keys.
class MyBean extends AbstractMyBean ... {
public static final String FIELD1 = 'field1'
private String field1
public mergeSettings(Map<String, Object> incoming) {
this.field1 = incoming.get(FIELD1);
// and so on, also do validation here....maybe put it on the abstract class
}
}
Its a lot of work for setters though...
I started toying with a new pattern that I called "type-safe object map". It's like a Java Map but the values have type. That allows you to define the keys that each class wants to read and get the values in a type safe way (with no run-time cost!)
See my blog for details.
The nice thing about this is that it's still a map, so you can easily implement inheritance, notification, etc.
You could use Generics to define what kind of settings this instance need. Something like this:
public abstract class MySuperClass<T extends MySettingsGenericType>{
public MySuperClass(T settings){
//get your generic params here
}
}
public class MyEspecificClass extends MySuperClass<T extends MySettingsForThisType>{
public MySuperClass(T settings){
super(settings);
//Get your espefic params here.
}
}
//and you could use this
BaseFunc doer = new ConcreteImplementation1(ConcreteSettingsFor1);
//I dont compile this code and write in a rush. Sorry if have some error...

Categories

Resources