I have the following object structure:
class Annotation;
class LabelAnnotation: inherits Annotation;
class TextAnnotation: inherits LabelAnnotation;
I would like to use "creator" objects to do some initialization on these object (This initialization depends on external settings so I don't want to do it in the constructor of these objects.)
In particular, when creating a LabelAnnotation I would like to do:
fontSize = AppDefaults.fontSize
So I'm writing a "creator":
class LabelAnnotationCreator {
LabelAnnotation create() {
annotation = LabelAnnotation()
annotation.fontSize = AppDefaults.fontSize
return annotation;
}
}
Now, I would like to create a TextAnnotationCreator. This is where I'm stuck: I can't use the LabelAnnotationCreator because it would create an instance of a LabelAnnotation, but on the other hand, I want to benefit from the initialization performed by the LabelAnnotationCreator.
class TextAnnotationCreator {
TextAnnotation create() {
annotation = TextAnnotation()
// I'm stuck here:
// can't do LabelAnnotationCreator().create()… ???
return annotation;
}
}
Obviously, this isn't the right pattern but I'm not sure how to find the correct one.
Thanks!
what do you think about this:
class TextAnnotation {
private final int someOtherArgs;
private final int fontSize;
public TextAnnotation(LabelAnnotation labelAnnotation, int someOtherArgs) {
this(someOtherArgs, labelAnnotation.getFontSize());
}
public TextAnnotation(int someOtherArgs, int fontSize) {
this.someOtherArgs= someOtherArgs;
this.fontSize = fontSize;
}
}
create a constructor on TextAnnotation that builds a object from a LabelAnnotation configuration. Then you can use it like this:
TextAnnotation text = new TextAnnotation(someArgs,fontSize);
or using your creator
class TextAnnotationCreator {
TextAnnotation create() {
return
new TextAnnotation(
new LabelAnnotationCreator().create(),
someOtherArgs
);
}
}
Related
I'm trying to pass new Object as method parameter and set it's variable at the same time.
This an okay solution but big and not nice...
EventBox evtbox = new EventBox();
evtbox.setFloorColor(floorColor);
scriptUtils.runScript("sc-cfrmd",evtbox);
and I need something like this to shorten it up a bit
scriptUtils.runScript("sc-cfrmd",new EventBox().setFloorColor(floorColor));
of course, logical way of doing this is just creating a constructor in EventBox class but I need to figure out way without use of constructors.
any tips are appreciated
You are looking for fluent interface
Usually, when you need to create a complex object you are implementing fluent interface with builder design pattern
For example:
import java.awt.Color;
public class EventBox {
private Color floorColor;
private EventBox() {
this.floorColor = null;
}
public Color getFloorColor() {
return floorColor;
}
private void setFloorColor(Color floorColor) {
this.floorColor = floorColor;
}
public static EventBoxBuilder builder() {
return new EventBoxBuilder();
}
public static class EventBoxBuilder {
private final EventBox box;
EventBoxBuilder() {
this.box = new EventBox();
}
public EventBoxBuilder setFloorColor(Color color) {
box.setFloorColor(color);
return this;
}
public EventBox build() {
return box;
}
}
}
....
scriptUtils.runScript("sc-cfrmd",EventBox.builder().setFloorColor(floorColor).build());
If you are able to use Lombok Framwork, such builder can be automatically generated on compile time by adding #Builder annotation to the EventBox class
You can use method chaining by adding methods as desired. Conventionally, leave the setters/getters as the standard practice to just do what their name says.
public EventBox withFloorColor(String floorColor) {
setFloorColor(floorColor);
return this;
}
scriptUtils.runScript("sc-cfrmd",new EventBox().withFloorColor(floorColor));
The most basic and simple solution is of course to create a method like
EventBox createFloorEventBox( String floorColor ) {
EventBox eb = new EventBox();
eb.setFloorColor( floorColor );
return eb;
}
and use it like
scriptUtils.runScript("sc-cfrmd", createEventBox( floorColor ) );
Besides the builder pattern/method chaining/fluent approach, you could also consider using lambdas in Java, like
void runScript(String something, Consumer<EventBox> boxInitializer) {
EventBox eb = new EventBox();
initializer.apply(eb);
...
}
and then call this like
runScript("something", eb -> eb.setFloorColor( floorColor ));
I have a library which parse URLs and extract some data. There is one class per URL. To know which class should handle the URL provided by the user, I have the code below.
public class HostExtractorFactory {
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
switch (host) {
case HostExtractorABC.HOST_NAME:
return HostExtractorAbc.getInstance();
case HostExtractorDEF.HOST_NAME:
return HostExtractorDef.getInstance();
case HostExtractorGHI.HOST_NAME:
return HostExtractorGhi.getInstance();
default:
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
}
The problem is users are requesting more URL to be parsed, which means my switch statement is growing. Every time someone comes up with a parser, I have to modify my code to include it.
To end this, I've decided to create a map and expose it to them, so that when their class is written, they can register themselves to the factory, by providing the host name, and the extractor to the factory. Below is the factory with this idea implemented.
public class HostExtractorFactory {
private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
if(EXTRACTOR_MAPPING.containsKey(host)) {
return EXTRACTOR_MAPPING.get(host);
} else {
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
public static void register(String hostname, HostExtractor extractor) {
if(StringUtils.isBlank(hostname) == false && extractor != null) {
EXTRACTOR_MAPPING.put(hostname, extractor);
}
}
}
And the user would use it that way:
public class HostExtractorABC extends HostExtractor {
public final static String HOST_NAME = "www.abc.com";
private static class HostPageExtractorLoader {
private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}
private HostExtractorABC() {
if (HostPageExtractorLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
HostExtractorFactory.register(HOST_NAME, this);
}
public static HostExtractorABC getInstance() {
return HostPageExtractorLoader.INSTANCE;
}
...
}
I was patting my own back when I realized this will never work: the user classes are not loaded when I receive the URL, only the factory, which means their constructor never runs, and the map is always empty. So I am back to the drawing board, but would like some ideas around getting this to work or another approach to get rid of this pesky switch statement.
S
Another option is to use the Service Loader approach.
Having your implementers add something like the following in ./resources/META-INF/services/your.package.HostExtractor:
their.package1.HostExtractorABC
their.package2.HostExtractorDEF
their.package3.HostExtractorGHI
...
Then in your code, you can have something like:
HostExtractorFactory() {
final ServiceLoader<HostExtractor> loader
= ServiceLoader.load(your.package.HostExtractor.class);
for (final HostExtractor registeredExtractor : loader) {
// TODO - Perform pre-processing which is required.
// Add to Map? Extract some information and store? Etc.
}
}
I would advice for you to learn about dependency injection (I love spring implementation). You will then be able to write an interface like
public interface HostExtractorHandler {
public String getName();
public HostExtractor getInstance();
}
Than your code can "ask" for all classes that implements this interface, you then would be able to build your map in the initialization phase of your class.
I would use the Reflections library to locate the parsers. They all appear to derive from the HostExtractor class, so use the library to locate all subtypes:
Reflections reflections = new Reflections("base.package");
Set<Class<? extends HostExtractor>> extractorTypes =
reflections.getSubTypesOf(HostExtractor.class);
Use the results to create the instances in your factory:
for (Class<? extends HostExtractor> c : extractorTypes) {
HostExtractor he = c.newInstance();
EXTRACTOR_MAPPING.put(he.getHostName(), he);
}
I made up the getHostName method, but it should be trivial to add to the HostExtractor base class.
This is a continuation from what I was working in Passing 1 to many parameters of same object type
I've gotten good feedback on that , I believe i have the improved the design . The whole code is at https://github.com/spakai/flow_input_builder
The requirement is simple : -
I need to build a set of input for different workflows using 1 or more outputs from previous workflows
I have a set of interfaces
public interface SwfInput {
}
public interface SwfOutput {
}
public interface Workflow<I extends SwfInput, O extends SwfOutput> {
public O execute(I input);
}
public interface Builder<I extends SwfInput> {
public I build();
}
Now , Say I have 3 flows which gets executed in sequence FlowA->FlowB->FlowC
FlowC needs mandatory output from FlowB but only optionally from FlowA
so I have a implementation for FlowCBuilder
public class FlowCInputBuilder implements Builder<FlowCInput> {
private final FlowBOutput mandatoryflowBOutput;
private FlowAOutput optionalflowAOutput;
public FlowAOutput getOptionalflowAOutput() {
return optionalflowAOutput;
}
public FlowCInputBuilder setOptionalflowAOutput(FlowAOutput optionalflowAOutput) {
this.optionalflowAOutput = optionalflowAOutput;
return this;
}
public FlowCInputBuilder(FlowBOutput mandatoryflowBOutput) {
this.mandatoryflowBOutput = mandatoryflowBOutput;
}
#Override
public FlowCInput build() {
FlowCInput input = new FlowCInput();
input.setMandatoryFromFlowB(mandatoryflowBOutput.getOutput1FromB());
if (optionalflowAOutput != null) {
input.setOptionalFromFlowA(optionalflowAOutput.getOutput2FromA());
}
return input;
}
}
one test i have written shows an example usage
FlowBOutput mandatoryflowBOutput = new FlowBOutput();
mandatoryflowBOutput.setOutput1FromB("iNeedThis");
FlowAOutput optionalflowAOutput = new FlowAOutput();
FlowCInput input = new FlowCInputBuilder(mandatoryflowBOutput)
.setOptionalflowAOutput(optionalflowAOutput)
.build();
I have not used static inner class for the Builder pattern.
Any suggestions are welcomed.
You should use static inner class. The key point of using this approach is that, the inner can directly access private properties of the object being constructed. This helps eliminating duplicated code since the builder does not need to maintain a long list of temporary state for the constructing. So, your code can be rewritten like this:
public class FlowCInput {
private int output1FromB; // suppose that it is int
private String output2FromA; // suppose that it is String
private FlowCInput() { }
//...
public static class FlowCInputBuilder implements Builder<FlowCInput> {
private final FlowCInput result;
public FlowCInputBuilder(FlowBOutput mandatoryflowBOutput) {
result = new FlowCInput();
// output1FromB is private but still accessed from here
result.output1FromB = mandatoryflowBOutput.getOutput1FromB();
}
public FlowCInputBuilder setOptionalflowAOutput(FlowAOutput optionalflowAOutput) {
// same for output2FromA
result.output2FromA = optionalflowAOutput.getOutput2FromA();
return this;
}
#Override
public FlowCInput build() {
return result;
}
}
}
As you see, the builder now holds only a FlowCInput object, it does not unnecessarily hold mandatoryflowBOutput and optionalflowAOutput as before.
I am refactoring a Hibernate mapped object Gadget to remove getIntFieldValue and setIntFieldValue and changing my code to retrieve that value from a DAO object, which is created using a Factory and to which a Gadget is passed.
public class GadgetPropertyAccessFactory {
public static GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
}
...
The test code looks like this:
//this mocks a Gadget
Gadget gadget = createGadget();
//this is to be replaced
when(gadget.getIntFieldValue()).thenReturn(2);
DoerClass doerClass = new DoerClass(null, gadget);
List<Result> doerResults = doerClass.produceResults();
for (Result doerResult : doerResults) {
//...
}
The DoerClass looks something like this
Session dbSessn;
Gadget gadget;
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
//this is to be replaced
int intFieldValue = this.gadget.getIntFieldValue()
//with
//GadgetPropertyDAO gadgPropDAO = GadgetPropertyAccessFactory.getGadgetPropertyDAO(this.dbSessn);
//int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
//generate List<Result> based on intFieldValue
}
My problem is that before I was able to conveniently mock what getIntFieldValue will return in produceResults but now that I am using a statically returned DAO, I do not know if it is possible to mock what GadgetPropertyDAO.getDeviceIntFieldValue(this.gadget) will return.
Is a mock possible without changing my method signatures (API)?
I agree with Tom G: Mockito and dependency injection (and arguably Java itself) are really designed for instances much more than static methods—it's the only way to take advantage of Java's polymorphic advantages. If you switch to making your factory an instance, it would look like this:
public class GadgetPropertyAccessFactory {
public GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
} // ...
}
public class DoerClass {
Gadget gadget;
Session dbSessn;
// Sets default implementation. Constructor injection would also work.
GadgetPropertyAccessFactory gpaFactory = new GadgetPropertyAccessFactory();
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
GadgetPropertyDAO gadgPropDAO =
gpaFactory.getGadgetPropertyDAO(this.dbSessn);
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
}
// in your test
DoerClass doerClass = new DoerClass(null, gadget);
GadgetPropertyAccessFactory mockFactory =
Mockito.mock(GadgetPropertyAccessFactory.class);
doerClass.gpaFactory = mockFactory;
// ...
Another option is to live with and manage your testing gap:
public List<Result> produceResults() {
return produceResultsInternal(gpaFactory.getGadgetPropertyDAO(this.dbSessn));
}
/** Visible only for testing. Do not call outside of tests. */
List<Result> produceResultsInternal(GadgetPropertyDAO gadgPropDAO) {
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
...which then allows you to test against produceResultsInternal with a mock, which gets you 80% tested with 20% of the grief.
I have an object which is created on the basis of few conditions, like this -
if (objType.equals("one-type")) {
targetTableName = "one_type_table";
sourceTableName = "one_type_parent";
unitTime = 1;
delayTime = 10;
} else if (objType.equals("two-type")) {
targetTableName = "two_type_table";
sourceTableName = "two_type_parent";
unitTime = 2;
delayTime = 20;
}
Config databaseConfig = new Config(targetTableName, sourceTableName, unitTime, delayTime);
I have been told that my module has to be saved from this monstrosity and the pattern that can save me is Factory. So I decided to use that and create an interface like this -
public interface ConfigInterface {
public String getSourceTable();
public String getTargetTable();
public int getDelay();
public int getUnitTime();
}
and also created a concrete implementation of this interface called Config.
Then create a factory to build this object -
public class ConfigFactory {
public ConfigInterface getConfig (String objType) {
if (objType.equals("one-type")) {
targetTableName = "one_type_table";
sourceTableName = "one_type_parent";
unitTime = 1;
delayTime = 10;
} else if (objType.equals("two-type")) {
targetTableName = "two_type_table";
sourceTableName = "two_type_parent";
unitTime = 2;
delayTime = 20;
}
Config databaseConfig = new Config(targetTableName, sourceTableName, unitTime, delayTime);
return databaseConfig;
}
}
Now I just shifted my monster code inside another function. Even that is fine but my config interface is not really a superclass for many subclasses which are being generated by factory class. There is only one type of Config object, it has all those 5 fields and thats it.
I am sure I am either using it wrong or its not the right solution for this problem. Can anyone tell me whats wrong or is there another magical pattern to solve my problem and get me those ship its.
Why not encapsulate Config subclasses OneType and TwoType that set these values in their constructor. Then change the factory to the following:
public Config getConfig (String objType) {
if (objType.equals("one-type")) {
return new OneType ();
} else if (objType.equals("two-type")) {
return new TwoType ();
}
Alternatively, I use this pattern with enums for this kind of situation:
enum ConfigType {
one-type ("one_type_table", "one_type_parent", 1, 10),
two-type ("two-type_table", "two_type_parent", 2, 20)
;
ConfigType (String table, String parent, int unit, int delay) {
...
}
String getTable () {
return this.table;
}
....
}
Now you can generalize the factory code and work in terms of static enum types instead of runtime evaluated strings.
public Config getConfig (ConfigType type) {
return new Config (type.getTable (),...
The size of the code in the question is small, so any implementation would be as efficient as the other.
If the objType comes from different class instances, say TypeOne and TypeTwo, then you could overload the getConfig() method, e.g.
public ConfigInterface getConfig(TypeOne type)
{
// Create and return the "one-type" object
}
public ConfigInterface getConfig(TypeTwo type)
{
// Create and return the "one-type" object
}
Otherwise, especially if there are many different types, consider creating an enum with all the possible values to objType, as opposed to using a string. You can then use a switch statement, which is more efficient than the consecutive string equals checks.