I am designing a validation module. It has 100 error codes(i.e. errcd_01, errcd_02,..,errcd_100) to be validated. In input I am getting a specific error code(i.e. errcd_01) out of above 100.
Module should perform validation for that specific error code.
I am using factory pattern.
/* Interface */
public interface validateErrCd {
void check_errcd();
}
/* Concrete classes implementing the same interface */
public class validateErrCd_01 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_01
}
}
public class validateErrCd_02 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_02
}
}
.
.
.
public class validateErrCd_100 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_100
}
}
/* Factory */
public class ErrorValidationFactory {
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
if(errorCode.equalsIgnoreCase("errcd_01")){
return new validateErrCd_01();
} else if(errorCode.equalsIgnoreCase("errcd_02")){
return new validateErrCd_02();
} ..
.......
else if(errorCode.equalsIgnoreCase("errcd_100")){
return new validateErrCd_100();
}
else {
return null;
}
}
}
/* I am using the Factory to get object of concrete class by passing an specific error code to be validated (i.e. "errcd_01"). */
public class FactoryPatternDemo {
public static void main(String[] args) {
ErrorValidationFactory errorFactory = new ErrorValidationFactory();
//get an object of validateErrCd_01 and call its check_errcd method.
validateErrCd errcd01 = errorFactory.getValidation("errcd_01");
//call check_errcd method of validateErrCd_01
errcd01.check_errcd();
}
}
Now due to multiple if/else inside Factory class ErrorValidationFactory, I am getting couple of CI/CD errors while performing mvn clean install.
e.g. [MethodLength] - checkstyle, Rule:CyclomaticComplexity - PMD.
So is there a way I can replace if/else, switch case kind of decision making inside factory which does not trigger above CI/CD errors in Java?
Note : If possible I would like to avoid reflection
You could use a Map:
public class ErrorValidationFactory {
private Map<String,Supplier<validateErrCd>> creators=new HashMap<>();
public ErrorValidationFactory(){
creators.put("errcd_100",validateErrCd_100::new);
//Same for others
}
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
return creators.getOrDefault(errorCode,()->null);
}
}
Supplier is a functional interface that contains a method returning an object. SomeClass::new or ()->new SomeClass() means that the constructor of the class will be used for that.
This allows to to create the instances later.
If you want to create the Map only once, you can make it static and populate it in a static initializer.
However, if you really want to dynamically get the constructors, you would need to use reflection.
Related
Guice newbie here, with a complicated scenario.
My company has a large number of constants of a given type (let's call them Thingy) that belong to different teams and are maintained in different parts of our application. However, we need to have a central registry that knows about all of them (let's call this the ThingyService). I am writing a base module that teams can either extend or install, with the purpose of allowing a team to register their Thingys, and giving them access to the ThingyService. This module takes as parameter a list of classes from which I can extract the Thingy constants, this part is working fine.
What I don't understand is how I can a) make each module know about each other module's list of Thingys and b) how I can create my ThingyService as a singleton that contains all of my Thingys. I have experimented with shared static state and with ThreadLocals, but I keep either breaking tests or breaking my main (play) application. In my naive understanding of Guice, I think I need a MultiBinder for the Thingys, but I don't see how I can share that between modules. Here's what I'd like to do:
class ThingyModule extends AbstractModule{
final Set<Class<?>> myThingyClasses; // this is populated in the constructor
private Set<Thingy> extractThingiesFromThingyClasses(){
// I have this working
}
#Provides #Singleton ThingyService thingyService(
Set<Thingy> thingys // all thingys, from all such modules
){
return new ThingyService(thingys);
}
protected void configure(){
extractThingiesFromThingyClasses().forEach(thingy->
// bind thingy to a global MultiBinder?
);
}
}
How can I make my ThingyService unique and global, with all the Thingys from the entire application? Note: I don't necessarily need my Thingys to be managed by Guice, the only place I need them is in ThingyService. Also, this is a play / scala application if that makes a difference, but my ThingyModule code lives in a library written in Java.
It turns out I omitted one important detail, Thingy has a type parameter, it's actually Thingy<T>, and that's the reason it didn't work before. By cheating and registering Thingy as raw type, and then also injecting it as raw type, I got it to work.
Here is a complete working example using JUnit 5 and AssertJ:
class ThingyModuleTest {
static class Thingy<T>{
private final T value;
Thingy(final T value) {this.value = value;}
#Override public boolean equals(final Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
final Thingy<?> thingy = (Thingy<?>) o; return Objects.equals(value, thingy.value); }
#Override public int hashCode() { return Objects.hash(value); }
}
#Singleton
static class ThingyService{
final Set<Thingy<?>> thingies;
#SuppressWarnings({"unchecked", "rawtypes"}) #Inject
ThingyService(Set<Thingy> thingies) {
this.thingies = ImmutableSet.copyOf((Set)thingies);
}
public Set<Thingy<?>> getThingies() { return thingies; }
}
abstract static class ThingyModule extends AbstractModule {
private final Set<Class<?>> classesToScan;
public ThingyModule(Class<?>... classes) {
this.classesToScan = ImmutableSet.copyOf(classes);
}
private Set<Thingy<?>> scanForThingies(){
return classesToScan.stream()
.flatMap(c-> Arrays.stream(c.getDeclaredFields()))
.filter(f->f.getType().isAssignableFrom(Thingy.class))
.filter(f-> Modifier.isStatic(f.getModifiers())&&Modifier.isFinal(f.getModifiers()))
.map(this::readThingy)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
}
#SuppressWarnings("unchecked")
private Optional<Thingy<?>> readThingy(final Field field) {
try{
field.setAccessible(true);
return Optional.ofNullable(field.get(null))
.filter(Thingy.class::isInstance)
.map(Thingy.class::cast);
} catch (IllegalAccessException e) { return Optional.empty(); }
}
#Override protected void configure() {
bind(ThingyService.class);
#SuppressWarnings("rawtypes") Multibinder<Thingy> multibinder = Multibinder.newSetBinder(binder(), Thingy.class);
scanForThingies().forEach(thingy -> multibinder.addBinding().toInstance(thingy));
}
}
static class ThingyModule1 extends ThingyModule {
public ThingyModule1() { super(Thingies1.class); }
static class Thingies1{
static final Thingy<Boolean> BooleanThingy = new Thingy<>(true);
static final Thingy<Integer> IntThingy = new Thingy<>(123);
}
}
static class ThingyModule2 extends ThingyModule {
public ThingyModule2() { super(Thingies2.class); }
static class Thingies2{
static final Thingy<String> StringThingy = new Thingy<>("hello");
static final Thingy<Long> LongThingy = new Thingy<>(123L);
}
}
#Test void validateThingyService() {
ThingyService thingyService = Guice.createInjector(new ThingyModule1(), new ThingyModule2())
.getProvider(ThingyService.class)
.get();
assertThat(thingyService).isNotNull()
.extracting(ts -> ImmutableList.copyOf(ts.getThingies()))
.asList()
.containsExactlyInAnyOrder(BooleanThingy, IntThingy, StringThingy, LongThingy);
}
}
I will mark this answer as accepted until somebody else provides a more idiomatic one.
For the sample code below...
Is there a way to chain instances of different classes? The example provided is a failed attempt for wiring up methods belonging to different class instances.
Also, In the same example, Client2 is sharing the error object with Client3. What is a more efficient way of sharing objects between subclasses and unassociated classes?
For clarity, i have also commented inline.
Thank You for your time and help.
Sample Code
public class StubRunner
{
public run(){
ClientFactory client = new ClientFactory();
//not correct. But, this is how i want to finally chain methods
//belonging to different class instances. Please advise.
client.getClient1().testClient1().getClient2().testClient2().assert(...);
}
}
public class ClientFactory
{
public Client1 getClient1(){return new Client1();}
public Client2 getClient2(){return new Client2();}
}
public class BaseClient
{
public Errors errors = null;
}
public class Client1 extends BaseClient
{
public void testClient1(){...}
}
public class Client2 extends BaseClient
{
public void testClient2()
{
//here i am directly passing the error object
//what is a better way?
//is there a more efficient way to make the SAME error object
//available to Client3
new Client3(this.errors).testClient3();
...
}
}
public class Client3 extends BaseClient
{
public Client3(Errors errors){this.errors = errors;}
public void testClient3(){...}
}
I would normally use lambda expressions for the cases when I want to program a short chain of method calls but I want the methods to change relatively to any kind of state. As for your scenario, each of your test would be a lambda expression and it would mean that I would pass the testClient4 method to the testClient3 method, the testClient3 method to the testClient2 method, etc. However, the code becomes more and more ugly as your chain of method calls becomes long.
=> You can use Fluent interface: you would have each method doing some logic and then returning an instance on which you can call the next inline methods you want to execute.
ClientFactory.getClient1() : Client1
Client1.testClient1() : Client1 (i.e. return this)
Client1.getClient2() : Client2
Client2.testClient2() Client2 (i.e. return this)
...
Obviously, each instance would need to have a reference to the next inline instance, knowing the one it will call (Client1 would have a reference to Client2, Client2 to Client3, etc).
This would work but I'm not a fan in this scenario! I'd say it's more a trick than clean coding. You should use fluent interface with each client separately unless one of your method is actually returning another instance:
client1.testClient1().testClient2().testClient3()
with each test method returning an instance of the next client if there is a good reason for it
but it wouldn't make sense to interpose the getClient methods between the test methods...
I am not really getting what your need really is, however in the actual state of the code it cannot even compile since you are trying to execute methods from a "Client" object from a void method return.
If you do not know how many clients and from which type you are going to get, I would simply use a list.
If you want to chain the clients using the 'testClient' method, then first this method should return the next client (which is a really awkward way to chain objects by the way), then you should start using more abstraction and overriding technics.
Basically, there's no need to know what object you are dealing with as long as it is a "BaseClient", but if you name the child methods "testClient1", "testClient2" etc ... you basically breaking it and you need to start thinking of what you are actually getting and adapt your code accordingly.
Finally, there's no need for a factory here, but if you want one, it should be static.
Here is a working example of this, again I do not really comprehend what you wanna do so it may not solve your issue, but it's a working solution to "chaining instances":
Main:
public class Foo
{
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
StubRunner stub = new StubRunner();
stub.run();
}
}
Stubrunner:
public class StubRunner implements Runnable
{
public void run(){
Object clients = ClientFactory.getClient1();
while (null!= clients && clients instanceof BaseClient) {
clients = ((BaseClient) clients).test();
}
}
}
Base:
public abstract class BaseClient
{
public Exception errors = null;
public BaseClient() {};
public BaseClient(Exception errors) {
this.errors = errors;
}
public abstract BaseClient test();
public void checkErrors() {
System.out.println(this.toString());
assert null == errors;
}
}
Client 1:
public class Client1 extends BaseClient
{
public BaseClient test(){
checkErrors();
return new Client2();
}
}
Client 2:
public class Client2 extends BaseClient
{
public BaseClient test()
{
checkErrors();
return new Client3(this.errors);
}
}
Client 3:
public class Client3 extends BaseClient
{
public Client3(Exception errors) {
super(errors);
}
public BaseClient test() {
checkErrors();
return null;
}
}
Factory:
public final class ClientFactory
{
private ClientFactory() {};
public static Client1 getClient1(){return new Client1();}
public static Client2 getClient2(){return new Client2();}
}
This outputs the following:
test.Client1#15db9742
test.Client2#6d06d69c
test.Client3#7852e922
Is there a way to chain instances of different classes? The example provided is a failed attempt for wiring up methods belonging to different class instances.
client.getClient1().testClient1().getClient2().testClient2().assert(...);
In order to chain methods like this, each method must return a reference to an object which supports the method which you want to call. However, each test method returns void.
In this case, method chaining seems very questionable because you are operating on different types. Often methods in a chain like this will just return this; so that another method can be called on the exact same object which started the chain.
Additionally, the names of your methods suggest that you are attempting to implement some automated testing of your code. You should learn about established testing techniques and libraries. In particular, JUnit is commonly used in Java and variations in other languages. There are certain techniques that are considered good practice when writing tests in frameworks such as this.
To be clear here, you should certainly not mix testing code with production code.
Also, In the same example, Client2 is sharing the error object with Client3. What is a more efficient way of sharing objects between subclasses and unassociated classes?
//here i am directly passing the error object
//what is a better way?
//is there a more efficient way to make the SAME error object
//available to Client3
new Client3(this.errors).testClient3();
The only way to send an object to a class is to pass a parameter, either to the constructor or to a method. This is how Java works.
Note that there is very little overhead because you are passing a reference variable. You are not copying the entire object. This means that both the current instance of Client2 and the new instance of Client3 have references to the same error object.
Now testClient1() could return the client factory and such. But that is very convoluted.
Another regulatory syntax is to override a context providing class.
new ClientFactory() {{
getClient1().testClient1();
getClient2().testClient2().assert(...);
}};
Here an initializing block ("anonymous constructor") will provide a context.
Then a bit of chaining can be done when testClient2 returns a Client2.
It can be a clean and useful design, for instance for my ambiguous grammar parser AnyParser on sourceforge.net (purely a craftmanship piece of work).
Thank you everyone for the great help. Your advise has allowed me to arrive at the following working solution. Maybe it is not the best, so seeking your valuable time and your expertise to direct to a better solution.
Given some remarks my naming convention being fishy, i have tried to amend them to a certain extent. Kindly bear with me.
Objective was:
To chain instances of different classes
To share objects between subclasses and unassociated classes
Problem description:
There are 4 tasks to be performed: Task1 to Task4.
Each task is unique. But sometimes, to complete a task we need to perform mixed Task: refer Task3 >> performMixedTasks()
To complete a piece of work we need to complete a set of Tasks.
State.java
public class State {
public Boolean ISAUDITED = false;
public int ERRORCODE = 0;
public String ERRORTEXT = "";
public void raise(int code, String msg){
this.ERRORCODE = code;
this.ERRORTEXT = msg;
}
}
BaseClient.java
public abstract class BaseClient {
public State state;
public BaseClient(){
this.state = new State();
}
public BaseClient(State state){
this.state = state;
}
public ClientFactory getTest(){
return new ClientFactory(state);
}
public Boolean Assert(){
if(state.ERRORCODE == 0){
System.out.println("Parsing was successful.");
return true;
}
else{
System.out.println("Parsing was not successful.");
return false;
}
}
public abstract BaseClient GoTo();
}
Task1.java
public class Task1 extends BaseClient {
public Task1(){ GoTo(); }
public Task1(State state){ super(state); GoTo(); }
public Task1 performTask1(){
if(!state.ISAUDITED)
{
System.out.println("perform Task1");
state.ISAUDITED = true;
}
return this;
}
#Override
public BaseClient GoTo() {
if(state.ISAUDITED){
new Task2(state).performTask2();
}
return this;
}
}
Task2.java
public class Task2 extends BaseClient{
public Task2(){ GoTo(); }
public Task2(State state){ super(state); GoTo(); }
public Task2 performTask2(){
if(state.ISAUDITED)
{
System.out.println("perform Task2");
state.ISAUDITED = false;
}
return this;
}
#Override
public BaseClient GoTo() {
if(!state.ISAUDITED){
new Task1().performTask1();
}
return this;
}
}
Task3.java
public class Task3 extends BaseClient {
public Task3(){ }
public Task3(State state){ super(state); }
public Task3 GoTo(){
if(!state.ISAUDITED) {new Task1(state).performTask1();}
System.out.println("Opening Task3");
return this;
}
public Task3 performTask3(){
try
{
this.GoTo();
System.out.println("Submitted Task3 Data");
}
catch(Exception e){
state.raise(1, e.getMessage());
}
return this;
}
public Task3 performMixedTasks(){
new Task4(state).performTask4();
this.performTask3();
return this;
}
}
Task4.java
public class Task4 extends BaseClient {
public Task4(){ }
public Task4(State state){ super(state); }
public Task4 GoTo(){
if(!state.ISAUDITED) {new Task1(state).performTask1();}
System.out.println("Opening Task 4");
return this;
}
public Task4 performTask4(){
try
{
this.GoTo();
System.out.println("Submitted Task 4 Data");
}
catch(Exception e){
state.raise(1, e.getMessage());
}
return this;
}
}
ClientFactory.java
public class ClientFactory {
State state;
public ClientFactory(){
state = new State();
}
public ClientFactory(State state){
this.state = state;
}
public Task3 loadTask3(){return new Task3(state);}
public Task4 loadTask4(){return new Task4(state);}
}
StubRunner1.java
public class StubRunner1 {
public static void main(String[] arg)
{
ClientFactory test = new ClientFactory();
test.loadTask3()
.performTask3()
.getTest()
.loadTask4()
.performTask4()
.Assert();
}
}
**RESULT IS**
perform Task1
Opening Task3
Submitted Task3 Data
Opening Task4
Submitted Task4 Data
Parsing was successful.
StubRunner2.java
public class StubRunner2 {
public static void main(String[] args) {
ClientFactory test = new ClientFactory();
test.loadTask3()
.performMixedTasks()
.Assert();
}
}
**RESULT IS**
perform Task1
Opening Task4
Submitted Task4 Data
Opening Task3
Submitted Task3 Data
Parsing was successful.
I have Utils class with method which throws exception when given data are incorrect.
I have also Service which uses this method, but the data are always generated in way that they will be correct during call. Data are generated by another utils class.
I understand that I should throw this exception from Utils class - but I can't throw it from Service - so I have to catch it.
How can I test this, simulate this exception?
All actions on this data are in private methods.
I want to avoid PowerMock, because I heard that it's a sign of bad design.
So the question is, how to implement this in good design?
From your description it looks like this:
class Service {
public void someMethod() {
Data data = AnotherUtils.getData();
try {
Utils.method(data); // exception never thrown
} catch(Exception e) {
// how to test this branch?
}
}
}
The goal would be something like this:
interface DataProvider {
Data getData();
}
interface DataConsumer {
void method(Data data);
}
class Service {
private final DataProvider dataProvider;
private final DataConsumer dataConsumer;
public Service(DataProvider dataProvider, DataConsumer dataConsumer) {...}
public void someMethod() {
Data d = dataProvider.getData();
try {
dataConsumer.method(data);
} catch(Exception e) {
}
}
}
This technique is called dependency injection.
Then, when testing, you can simply provide a mock implementation for this DataProvider interface that does return faulty data:
#Test(expected=Exception.class)
public void myTest() {
DataProvider badDataProvider = () -> new BadData(); // Returns faulty data
Service service = new Service(badDataProvider, Utils.getConsumer());
service.someMethod(); // boom!
}
For the non-testing code, you could simply wrap the utils classes you already have in these interfaces:
class AnotherUtils {
public static Data getData() {...}
public static DataProvider getProvider() {
return AnotherUtils::getData;
}
}
...
Service service = new Service(AnotherUtils.getProvider(), Utils.getConsumer());
Here is an approach where you want to introduce Dependency Injection, but for whatever reason you don't want to change legacy code.
Say you have some static utility method like so:
class Utils{
public static Something aMethod(SomethingElse input) throws AnException{
if(input.isValid())
return input.toSomething();
throw new AnException("yadda yadda");
}
}
And you have a class that uses that utility method. You can still inject it with a FunctionalInterface.
#FunctionalInterface
interface FunctionThrowsAnException<K,V> {
V apply(K input) throws AnException;
}
class Service {
private final FunctionThrowsAnException<SomethingElse,Something> func;
Service(FunctionThrowsAnException<SomethingElse,Something> func){
this.func = func;
}
Something aMethod(SomethingElse input){
try{
return func.apply(input);
}catch(AnException ex){
LOGGER.error(ex);
}
}
}
Then use it like this:
new Service(Utils::aMethod).aMethod(input);
To test it:
new Service(x -> { throw new AnException("HA HA"); }).aMethod(input);
Consider a method
public void doSomething(String actionID){
switch (actionID){
case "dance":
System.out.print("I'm dancing");
break;
case "sleep":
System.out.print("I'm sleeping");
break;
default:
System.out.print("I've no idea what I'm doing");
}
The implementation of the method depends on the value of the parameter. Is there a more elegant way to do this, or a different design pattern to replicate the behaviour?
If the caller decides what logic is executed by passing different strings, then why not just have them call different methods:
public void doSomething(String actionID) {...}
...
doSomething("dance");
doSomething("sleep");
VS.:
public void dance() {...}
public void sleep() {...}
...
dance();
sleep();
It seems like you're unnecessarily funnelling all the calls into doSomething
But the strings might not always be literals. What if you're taking them from the console?
You could provide static mappings from the strings to the corresponding functions:
class MyClass {
private static final Map<String, Consumer<MyClass>> map = new HashMap<>();
static {
map.put("sleep", MyClass::sleep);
map.put("dance", MyClass::dance);
}
public void doSomething(String actionID) {
map.getOrDefault(actionID, MyClass::doNothing).accept(this);
}
public void dance() {
System.out.print("I'm dancing");
}
public void sleep() {
System.out.print("I'm sleeping");
}
private void doNothing() {
System.out.println("I've no idea what I'm doing");
}
}
This makes scenarios where you have a lot of switch cases a lot cleaner.
Introduce an interface, e.g.
public interface HumanState {
public void tellMeWhatYouAreDoing();
}
encapsulate the logic in different implementations
public class DancingState implements HumanState {
#Override
public void tellMeWhatYouAreDoing() {
System.out.println("I'm dancing");
}
}
public class SleepingState implements HumanState {
#Override
public void tellMeWhatYouAreDoing() {
System.out.println("I'm sleeping");
}
}
public class UnknownState implements HumanState {
#Override
public void tellMeWhatYouAreDoing() {
System.out.println("I've no idea what I'm doing");
}
}
and use a map. E.g.
public class HumanStateExample {
public static void main(String[] args) {
HumanStateExample humanStateExample = new HumanStateExample();
humanStateExample.doSomething("dance");
humanStateExample.doSomething("sleep");
humanStateExample.doSomething("unknown");
}
private final HashMap<String, HumanState> humanStateMap;
public HumanStateExample(){
humanStateMap = new HashMap<String, HumanState>();
humanStateMap.put("dance", new DancingState());
humanStateMap.put("sleep", new SleepingState());
}
public void doSomething(String action) {
HumanState humanState = humanStateMap.get(action);
if(humanState == null){
humanState = new UnknownState();
}
humanState.tellMeWhatYouAreDoing();
}
}
I'm not sure how the pattern is called, but it is very useful if you need to delegate the method call based on more than one parameter:
Create a lot of handlers where each one knows when it is responsible for handling a call. Then just loop through them and invoke the first one matching the parameter.
edit: I renamed the class from FancyParameterActionFactory to FancyParameterActionUtility: it is not a factory, the name was misleading
//Your method, but this time with a complex object, not with a simple string.
public void doSomething(FancyParameterObject fpo){
FancyParameterActionUtility.invokeOn(fpo);
}
//The utility which can handle the complex object and decides what to do.
public class FancyParameterActionUtility{
public Interface FPAHandler{
void invoke(FancyParameterObject fpo);
boolean handles(FancyParameterObject fpo);
}
//Omitted: Different implementations of FPAHandler
public static List<FPAHandler> handlers = new LinkedList<>();
static{
handlers.add(new DanceHandler());
handlers.add(new SleepHandler());
//Omitted: Different implementations of FPAHandler
}
public static void invokeOn(FancyParameterObject fpo){
for(FPAHandler handler:handlers){
if (handler.handles(fpo)){
handler.invoke(fpo);
return;
}
}
//Default-Behavior
}
}
Here is a simple implementation of the command pattern based your sample problem. I define a general AbstractCommand abstract class which contains two methods. The first method, createCommand(), instantiates a command class based on an input string name. This is how you can delegate your string input to create the right type of command. The second method is doAction(), and this is left undefined, to be implemented later on by specific concrete command classes.
public abstract class AbstractCommand {
public static AbstractCommand createCommand(String name) {
try {
String clsName = name + "Command";
Class<?> cls = Class.forName(clsName);
AbstractCommand command = (AbstractCommand) cls.newInstance();
return command;
}
catch (Exception e) {
System.out.println("Something went wrong.");
}
}
public abstract void doAction();
}
public class DanceCommand extends AbstractCommand {
public void doAction() {
System.out.println("I'm dancing");
}
}
public class TestCommandPattern {
public void doSomething(String actionID) {
AbstractCommand cmd = AbstractCommand.createCommand(actionID);
cmd.doAction();
}
public static void main(String[] args) {
TestCommandPattern test = new TestCommandPattern();
test.doSomething("Dance"); // should print "I'm dancing"
}
}
Now that this framework has been setup, you could easily add other commands for the various types of actions in your original problem. For example, you could create a SleepCommand class which would output I'm sleeping, or do whatever action you wish.
I am trying to use RabbitMQ and based on different message, different implements should be called.
I set the message format as of JSON, and there is a field "callType", the value of it is the class name implements a common interface. e.g, all implementations have implements interface "Task", and I have implementation of "TaskImp1","TaskImp2","TaskImp3".
So the code should be like
if (callType=="TaskImp1")
((Task)TaskImp1).runTask()
if (callType=="TaskImp2")
((Task)TaskImp2).runTask()
if (callType=="TaskImp3")
((Task)TaskImp3).runTask()
But could it be more flexible? If later I develop a new one "TaskImp4", I don't want to change the calling code, is it possible to have java automatically pick the right implementation since the callType is actually the class name of the implementation.
Yes, for example, through Java reflection (What is reflection and why is it useful?). Reflection has a performance cost though (Java Reflection Performance)
Sure: put your Task instances in a map:
private Map<String, Task> tasksByName = new HashMap<>();
...
tasksByName.put("TaskImp1", new TaskImp1());
tasksByName.put("TaskImp2", new TaskImp2());
tasksByName.put("TaskImp3", new TaskImp3());
...
String callType = message.getCallType();
Task task = tasksByName.get(callType);
task.runTask();
Also, read How do I compare strings in Java?
You have an opportunity to use Strategy here. So for e.g. you could do like:
public class MyTask {
private Task task;
public MyTask(Task task) {
this.task = task;
}
public void doSomething() {
task.runTask();
}
public static void main(String args[]) {
MyTask task = new MyTask(new TaskImpl1());//or even you could use setTask() api to inject task at runtime rather than doing cast on compile time.
task.doSomething();
task = new MyTask(new TaskImpl2());
task.doSomething();
task = new MyTask(new TaskImpl3());
task.doSomething();
}
}
In this way you could make your code extensible. Tomorrow if you have taskImpl4, you could code it independently and inject in MyTask without even touching MyTask class implementation.
As #ovdsrn already said you can use reflection. Simple example would be something like (the key is getTask static method. Also, note that, when you are using Class.forName you must specify whole "path" (package) for your class)
// ITask.java
package main;
public interface ITask {
void doSomething();
}
// Task1.java
package main;
public class Task1 implements ITask {
#Override
public void doSomething() {
System.out.println("Task1");
}
}
// Task2.java
package main;
public class Task2 implements ITask {
#Override
public void doSomething() {
System.out.println("Task2");
}
}
// main
package main;
public class JavaTest {
private static ITask getTask(String name) {
try {
Class<?> cls = Class.forName(name);
Object clsInstance = (Object) cls.newInstance();
return (ITask)clsInstance;
} catch (Exception e) { // you can handle here only specific exceptions
return null;
}
}
public static void main(String[] args) {
String name = args.length > 0 ? args[0] : "Task2";
ITask task = getTask("main." + name);
if (task != null) {
task.doSomething();
}
else {
System.out.println("can not make instance of class: " + name);
}
}
}