recommended design pattern java dynamic invocation - java

I have the following db table:
id method_id
1 1
1 2
1 3
and 2 classes:
EmailController and Smscontroller
in my code, I need to iterate over the table and according to the method_id (1 or 2) to invoke the send method of either EmailController or Smscontroller.
What is the recommended design pattern for it?
EDITED
There could be 100 methods! I put only 3. This is why I do not prefer the if else.
As well, the object that I send to EmailController send method is different than the one that I send to SmsController send method.
In EmailController I need to send User object.
In SmsController I need to send Manager object

I can't think of a design pattern. But for ultimate flexibility you can have a design similar to this:
public interface Sendable /* or Sender, SendingManager, etc. */ {
public int getId();
public void send();
}
public class EmailController implements Sendable {
}
public class SmsController implements Sendable {
}
public class Sendables {
private Map<Integer, Sendable> sendables = new HashMap<Integer, Sendable>();
public void addSendable(Sendable s) {
this.sendables.put(s.getId(), s);
}
public void sendById(Integer id) {
this.sendables.get(id).send();
}
}
Then you can use it like this:
Sendables sendables = new Sendables();
sendables.add(new EmailController());
sendables.add(new SmsController());
sendables.add(new ChatController());
// etc.
Row row = table.getRow(...); // let's assume this gets a row from your table
sendables.send(row.getId());
Another solution could be to have an extra table like this:
TABLE: CLASS_NAMES
method_id class_name
1 "com.foo.SmsController"
2 "com.foo.EmailController"
And then pass class_name to Class.forName and let it instantiate the appropriate controller for you to use.
EDIT: A reflection-based version of the code as suggested by Luis. Note that for production use you should ensure that the passed parameters are valid (not null, etc.) and also handle exceptions with rigor.
TABLE: CLASS_NAMES
method_id class_name param_class_name
1 "com.foo.SmsController" "com.foo.Manager"
2 "com.foo.EmailController" "com.foo.User"
SendManager
public class SendManager {
private static final String SEND_METHOD_NAME = "send";
/* DAO for the CLASS_NAMES tables */
private ClassNameDAO classNameDao;
/**
* Gets the row corresponding to methodId, for example
* (1, "com.foo.SmsController", "com.foo.Manager") then using reflection
* instantiates an instance of SmsController and invokes its send method
* with <code>param</code> passed to it.
*/
public void send(int methodId, Object param) throws Exception {
ClassNameRow classNameRow = classNameDao.findByMethodId(methodId);
String senderParameterClassName = className.senderParameterClassName();
Class paramClass = Class.forName(senderParameterClassName);
if (!paramClass.isInstance(param)) {
throw new IllegalArgumentException("methodId and param are not compatible");
}
String senderClassName = classNameRow.getSenderClassName();
Class senderClass = Class.forName(senderClassName);
/* Your sender classes must be JavaBeans and have no-arg constructors */
Object sender = senderClass.newInstance();
Class paramClass = Class.forName(senderParameterClassName);
Method send = senderClass.getMethod(SEND_METHOD_NAME, paramClass);
send.invoke(sender, param);
}
}
Sample Usage
SendManager sendManager = new SendManager();
Manager m = ...;
sendManager.send(1, m);
User u = ...;
sendManager.send(2, u);

How about this:
abstract class Controller {
public static Controller getInstance(int methodId) {
switch (methodId) {
case 1:
return new EmailController();
case 2:
return new SmsController();
default:
return null;
}
}
public abstract void send();
}
class EmailController extends Controller {
#Override
public void send() {
System.out.println("sending email");
}
}
class SmsController extends Controller {
#Override
public void send() {
System.out.println("sending sms");
}
}
And use it like this:
Controller.getInstance(methodId).send();
I'm using the Strategy pattern and the Factory Method pattern in my solution.

Strategy Pattern
http://johnlindquist.com/2010/08/25/patterncraft-strategy-pattern/
http://en.wikipedia.org/wiki/Strategy_pattern

Related

Open close solid principle conditional fails

According to the SOLID principle open and close principle says class is open for extension and closed for modification.
So I am allowed to add new logic based on new if-else conditions?
If I will not use conditionals so how will I identify based on which condition which action has to be applied
public interface TemplateClassification {
QuesObj processTemplate(RawPart rawPart);
}
public class Template1 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
}
}
public class Template2 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
}
}
public class TemplateInfo {
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification() {
return templateClassification;
}
public void setTemplateClassification(TemplateClassification templateClassification) {
this.templateClassification = templateClassification;
}
}
public class TemplateProduct {
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart){
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
}
}
#RestController
class Pg {
#Autowired
TemplateInfo templateInfo;
#Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart){
QuesObj ques = null;
if(rawPart.getId() == 1){
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(rawPart.getId() == 2){
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(tempId == 3){
// coming soon
}
}
}
How can i eliminte the if else condition so that it can follow open-close principle
To implement the "O" in SOLID, you can follow the below, which includes the "S" as well.
We are going to use polymorphism and inheritance.
Step 1 :
Create an interface that will sit in front of the classes that will be responsible in creating the QuesObj. We are going to need this, because down the line the code could receive a creator (child class) when id is 1,2 or 3.
It is important to note that QuesObj was identified because that is being returned on your original if statements and this is the reason we are allowed to continue with this approach.
public interface QuesObjCreator {
QuesObj calculate(RawPart rawPart);
}
Step 2:
Create individual class that creates the QuesObj in different ways in The only role of that class is to create the object.
public class QuesObjCreatorFor1 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
public class QuesObjCreatorFor2 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
Step 3:
Create a factory to return a QuesObjCreator. The factory will be returned to your main code/service.
public class QuesObjectCreatorFactory {
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory() {
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
}
public static QuesObjCreator getQuesObjCreator(final int number) {
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null) {
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
}
return quesObjCreator;
}
}
Step 4:
Use Factory to create the QuesObj
public class Pg {
public void doProcessing(RawPart rawPart){
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
}
}
Collectively we achieved the Single responsibility across all classes and are decoupled.
It is easy to maintain cause now you can add more options to create QuesObj and none of the code would change, thus achieving open for extensibility/closed for modification.
It all boils down to the Factory and Map that has the creators. The map has to be populated with all the creator instances. With Spring this can be very easy, as Spring can scan your project, find beans of a specific type, give you a List and then you can convert it to a map.
Your case has nothing to do with SOLID. According to open-closed principle, you cannot allow modification to your class IN RUNTIME that can break its behavior.
In your case I suggest the following:
Add getId() method to your TemplateClassification interface.
Make each TemplateClassification implementation a bean
Add bean that will form the map of templates for you
#Bean
public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates) {
return algorithms.stream()
.collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
}
Autowire Map<Integter, TemplateClassification> templates to your controller and find the required template by id.

How to create a 'getter' using a lambda expression

I have an object in use throughout my codebase, UnsecureObject. This object is auto-generated with no getters/setters, and all member fields are public. So editing is done by doing something like the following:
unsecureObjInstance.firstName = "Jane";
This is not desirable for numerous reasons that I probably don't have to explain here. But using this generated class is required for some other technical details with our messaging pipeline that I won't go into.
I have a desire is to leverage a mapping utility written by someone else on my team to convert this UnsecureObject to a pojo that I am writing.
An example of the mapper in action (with two normal classes w/ getters/setters) would be something like:
new MapperBuilder<>(PojoOne.class, PojoTwo.class)
.from(PojoOne::getName).to(PojoTwo::getFirstName)
.build();
This will map the PojoOne#name field to the PojoTwo#firstName field.
Is there a way to translate this to input my UnsecureObject here? I have tried something like the following:
new MapperBuilder<>(UnsecureObject.class, SecureObject.class)
.from(u -> u.firstName).to(SecureObject::getFirstName)
.build();
But get an error here, something along the lines of 'u -> u.firstName' could not be invoked.
So the question is:
Is there a way to essentially "construct" a getter on the fly using these public members? So in the .from() method, I can construct the call to look like a standard method that will yield my u.firstName?
Thanks for the help!
EDIT:
this is approx what the MapperBuilder class looks like (attempted to edit a bit to take away project specific wrappers/simplify)
/**
* This class is used to convert between POJO getter method references to the corresponding field names.
* #param <B> type
*/
public interface PojoProxy<B> {
/**
* Invokes the given getter method and returns information about the invocation.
* #param getter the getter to invoke
* #return information about the method invoked
*/
<T> GetterInvocation<T> invokeGetter(Function<B, T> getter);
}
/**
* Stores information about a method invocation.
* #param <T> method return type
*/
public interface GetterInvocation<T> {
public Class<T> getReturnType();
public String getFieldName();
}
/**
* A builder class to create {#link Mapper} instances.
* #param <FROM> source type
* #param <TO> target type
*/
public class MapperBuilder<FROM, TO> {
private final Class<FROM> _fromClass;
private final Class<TO> _toClass;
private final PojoProxy<FROM> _fromProxy;
private final PojoProxy<TO> _toProxy;
public MapperBuilder(Class<FROM> fromClass, Class<TO> toClass) {
_fromClass = fromClass;
_toClass = toClass;
//We will pretend there is an impl that provides the proxy.
//Proxies wrap the from and to classes in order to get reflection information about their getter calls.
_fromProxy = PojoProxy.of(fromClass);
_toProxy = PojoProxy.of(toClass);
}
public <FROM_VALUE> ToFieldBuilder<FROM_VALUE> from(Function<FROM, FROM_VALUE> getter) {
GetterInvocation<FROM_VALUE> methodInvocation = _fromProxy.invokeGetter(getter);
return new ToFieldBuilder<>(methodInvocation.getFieldName(), methodInvocation.getReturnType());
}
public class ToFieldBuilder<FROM_VALUE> {
private final String _fromFieldPath;
private final Class<FROM_VALUE> _fromClass;
public ToFieldBuilder(String fromFieldPath, Class<FROM_VALUE> fromClass) {
_fromFieldPath = fromFieldPath;
_fromClass = fromClass;
}
public <TO_VALUE> FromFieldBuilder<FROM_VALUE, TO_VALUE> to(Function<TO, TO_VALUE> getter) {
//similar to above, but now using a FromFieldBuilder.
}
}
public class FromFieldBuilder<FROM_VALUE, TO_VALUE> {
//impl..
}
}
I dont see MapperBuilder.from() method details, you can try this implementation of MapperBuilder.java Function (getter) -> (BiConsumer) setter
public class MapperBuilder<S, D> {
private final S src;
private final D dest;
public MapperBuilder(S src, Class<D> dest) {
this.src = src;
try {
this.dest = dest.newInstance();
} catch (Exception e) {
throw new RuntimeException("Required default constructor for: " + dest);
}
}
//getter - function to get value from source instance
//setter - biConsumer to set value to destination instance
//example - map(SrcClass::getSrcValue, DestClass::setDestValue)
public <V> MapperBuilder<S, D> map(Function<S, V> getter, BiConsumer<D, V> setter) {
setter.accept(dest, getter.apply(src));
return this;
}
public D build() {
return dest;
}
}
SrcClass.java some source class:
public class SrcClass {
private String srcValue;
public String getSrcValue() {
return srcValue;
}
public void setSrcValue(String srcValue) {
this.srcValue = srcValue;
}
}
DestClass.java some destination class:
package com.example.demo;
public class DestClass {
private String destValue;
public String getDestValue() {
return destValue;
}
public void setDestValue(String destValue) {
this.destValue = destValue;
}
}
DemoApplication.java demo:
public class DemoApplication {
public static void main(String[] args) {
SrcClass src = new SrcClass();
src.setSrcValue("someValue");
DestClass dest = new MapperBuilder<>(src, DestClass.class)
.map(SrcClass::getSrcValue, DestClass::setDestValue)
// map another fields
.build();
// for your UnsecureObject case
UnsecureObject unsecureObject = new MapperBuilder<>(src, UnsecureObject.class)
.map(SrcClass::getSrcValue,
(unsecure, srcValue) -> unsecure.unsecureValue = srcValue)
.build();
}
}

How to dynamically handle commands in a chat program?

My question is more of a design issue than anything else. I'm currently developing a classic Server-Client chat program in Java. Everything is fine until I get to the commands. I thought it would be convenient for users to send commands that would then be treated by the server for changing their nickname for example. The thing is I want to make flexible code and above all, object-oriented code. To avoid endless if/else if statements to know what command was typed I believe it would be better to create a class for each command which inherit from a superclass Command. Then I could return the specific command through a getCommand() function overriden in all subclasses. But it does not solve my problem at all. The server still needs to test with instanceof what command has been returned. One way to do it dynamically would be to sort of auto downcasting it from the superclass Command and then call the appropriate function in the server class. For example:
public void processCommand(CommandNick c) {}
public void processCommand(CommandKick c) {}
But I haven't found any proper way of doing that and even if I did, I feel like there's still a design issue here. And I am convinced there is a nice and flexible way to do it but days weren't enough for me to figure it out. Any ideas? Thanks in advance! :)
I assume your server receives the message as an Object with a Sender and a String. Create your Command classes, and in the server init code, make a HashMap<String, AbstractCommand> with a String as key and your AbstractCommand class as value. Your commands should extend this class. Register all your commands, like so:
commandRegistry.put("help", new HelpCommandHandler());
I assume a command is a message with a ! before it. So when you receive a message, check if it is a command:
Message message = (Your Message)
String messageBody = message.getBody();
Sender messageSender = message.getSender();
if(messageBody.startsWith("!")) {
// Split the message after every space
String[] commandParts = messageBody.split(" ");
// The first element is the command base, like: !help
String baseCommand = commandParts[0];
// Remove the first character from the base, turns !help into help
baseCommand = baseCommand.substring(1, baseCommand.length());
// Creates a new array for the arguments. The length is smaller, because we won't copy the command base
String[] args = new String[commandParts.length - 1];
// Copy the elements of the commandParts array from index 1 into args from index 0
if(args.length > 0) {
System.arraycopy(commandParts, 1, args, 0, commandParts.length - 1);
}
// Your parse method
processCommand(sender, baseCommand, args);
}
public void processCommand(Sender sender, String base, String[] args) {
if(commandRegistry.containsKey(base)) {
commandRegistry.get(base).execute(sender, args);
} else {
// Handle unknown command
}
}
public abstract class AbstractCommand {
public abstract void execute(Sender sender, String[] args);
}
Sample implementation. I assume your server is a Singleton, and you can get on Object of it with Server.get() or any similar method.
public class HelpCommandHandler extends AbstractCommand { /* !help */
#Override
public void execute(Sender sender, String[] args) {
sender.sendMessage("You asked for help."); // Your code might not work like this.
}
}
public class ChangeNickCommandHandler extends AbstractCommand { /* !changenick newNick */
#Override
public void execute(Sender sender, String[] args) {
// I assume you have a List with connected players in your Server class
String username = sender.getUsername(); // Your code might not work like this
Server server = Server.get(); // Get Server instance
server.getUsers().get(username).setNickname(args[0]); // Argument 0. Check if it even exists.
}
}
// Server class. If it isn't singleton, you can make it one like this:
public class Server {
private static Server self;
public static Server init(/* Your args you'd use in a constructor */) { self = new Server(); return get(); }
public static Server get() { return self; }
private List<User> users = new List<User>();
private HashMap<String, AbstractCommand> commandRegitry = new HashMap<>();
// Make construcor private, use init() instead.
private Server() {
commandRegistry.put("help", new HelpCommandHandler());
commandRegistry.put("changenick", new ChangeNickCommandHandler());
}
// Getters
public List<User> getUsers() {
return users;
}
public HashMap<String, AbstractCommand> getRegistry() {
return commandRegistry;
}
}
This is a bit of pseudo code to illustrate that your controller doesn't need to know about the command processors (no need for instanceof).
abstract class CommandProcessor {
/* return boolean if this Command processed the request */
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat);
}
/* Handle anything */
public class CommandRemainder extends CommandProcessor {
#Override
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat) {
chat.appendText("[" + user.getName() + "] " + command);
return true;
}
}
/* Handle color changing */
public class CommandColorizer extends CommandProcessor {
protected static List<String> ALLOWED_COLORS = new ArrayList<>(Arrays.asList("red", "blue", "green"));
#Override
public static boolean processCommand(String command, User user, Properties chatProperties, Chat chat) {
if ("fg:".equals(command.trim().substring(0,3)) {
String color = command.trim().substring(3).trim();
if (ALLOWED_COLORS.contains(color)) {
chat.setForeground(color);
}
return true;
}
return false;
}
}
public class ChatController {
protected Chat chat = new Chat();
protected User user = getUser();
protected Properties chatProperties = getChatProperties();
protected List<CommandProcessor> commandProcessors = getCommandProcessors();
{
chat.addChatListener(new ChatListener(){
#Override
public void userChatted(String userChatString) {
for (CommandProcessor processor : commandProcessors) {
if (processor.processCommand(userChatString, user, chatProperties, chat)) {
break;
}
}
}
});
}
List<CommandProcessor> getCommandProcessors() {
List<CommandProcessor> commandProcessors = new ArrayList<>();
commandProcessors.add(new CommandColorizer());
commandProcessors.add(new CommandRemainder()); // needs to be last
return commandProcessors;
}
}

Stub void method in Spock which populate

How can I stub/mock a void method which populates some objects that would be used later.
class RequestHelper{
public void populateOrderRequestBody(String product,String quantity,String profile, OrderType orderType){
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
} }
class ServiceClient{
RequestHelper rh;
public void docall(Order order){
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(),order.getQuantity(),order.getProfile(),orderType);
/**
* some other code
**/
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}}
Now I want to test ServiceClient class which call RequestHelper to populate orderType object. How to stub the method of RequestHelper class.
In this particular case if no verification will be done to rh filed you just need a plain Stub - just to ensure no NullPointerException is thrown when testing the docall method. Mock will also be sufficient however is more advanced object and using it here is pointless. When it comes to Spy it's used to verify invocations on a real (in terms of not being mocked) object. Have a look at the example below - runs smoothly just with Stub:
#Grab('org.spockframework:spock-core:1.0-groovy-2.4')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
service.rh = Mock(RequestHelper)
when:
service.doCall(new Order())
then:
noExceptionThrown()
}
}
class Order {
String product
String quantity
String profile
}
class OrderType { }
class FACTORY {
static OrderType CreateOrderType = new OrderType()
}
class RequestHelper {
public void populateOrderRequestBody(String product, String quantity, String profile, OrderType orderType) {
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
}
}
class ServiceClient {
RequestHelper rh;
public void doCall(Order order) {
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(), order.getQuantity(), order.getProfile(), orderType);
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}
}
Very similar to Opal's answer but using a mock order..
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
def order = Mock(Order)
order.getProduct() >> 'product1'
order.getProfile() >> 'profile1'
order.getQuantity() >> 3
service.rh = Mock(RequestHelper)
when:
service.doCall(order)
then:
noExceptionThrown()
1 * rh.populateOrderRequestBody('product1',3,'profile1',FACTORY.CreateOrderType)
}
}
Note that this only works if the CreateOrderType.equals() will return true

Use the command line to make new objects

In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}

Categories

Resources