How to invoke enum value specific method outside of enum? - java

I have enum like this:
public enum Email{
WELCOME,
LOGIN
}
EmailService has following method signature:
public void sendEmail(String from, String subject, String[] to, Map<String, String> props, String templateFileName)
I want to have API like this:
Email.WELCOME.send(from, subject, to, welcomeProp1, welcomeProp2....)
Email.LOGIN.send(from, subject, to, loginProp1, loginProp2....)
To acheve this I tried to add specific methods to enum fields:
public enum Email{
WELCOME{
public void send(String param1,String param2,String param3,String param4){
....
}
},
LOGIN{
public void send(String anotherParam1,String anotherParam2,String anotherParam3){
....
}
}
}
But I found out that I could not invoke this methods outside of enum. To acheve it I need to create abstract method and override in each enum value. But problem that signature of these methods are different and it is impossible to do it.
Any ideas?

You can use polymorphism for in such case. First of all, define some interface, for instance:
public interface Message {
}
Then you should add an abstract method to the enum:
public abstract void send(Message message);
After that, create two child classes - the first one is for WELCOME and the second one is for LOGIN:
class WelcomeMessage implements Message {
private String param1;
private String param2;
private String param3;
private String param4;
// constructor, getters
}
class LoginMessage implements Message {
private String anotherParam1;
private String anotherParam2;
private String anotherParam3;
// constructor, getters
}
Then add implementations of send() method:
public enum Email {
WELCOME {
public void send(Message message) {
WelcomeMessage wm = (WelcomeMessage) message;
....
}
},
LOGIN {
public void send(Message message) {
LoginMessage lm = (LoginMessage) message;
....
}
}
}
UPD.
#gstackoverflow mentioned that it's possible to invoke methods with "incorrect" implementation. I guess I know how to prevent this.
public enum Email {
WELCOME {
protected void sendInternal(Message message) {
WelcomeMessage wm = (WelcomeMessage) message;
....
}
protected Class<? extends Message> getSupportedClass() {
return WelcomeMessage.class;
}
},
LOGIN {
protected void sendInternal(Message message) {
LoginMessage lm = (LoginMessage) message;
....
}
protected Class<? extends Message> getSupportedClass() {
return LoginMessage;
}
};
public static void send(Message message) {
for (Email email : values()) {
if (email.getSupportedClass().equals(message.getClass()) {
email.sendInternal(message);
}
}
}
protected abstract void sendInternal(Message message);
protected abstract Class<? extends Message> getSupportedClass();
}

One solution is to make all the methods take exactly the same object, they just use different parameters from it.
class EmailDetails {
String param1;
String param2;
String param3;
String param4;
String anotherParam1;
String anotherParam2;
String anotherParam3;
}
public enum Email {
WELCOME {
public void send(EmailDetails details) {
System.out.println("Welcome!!");
}
},
LOGIN {
public void send(EmailDetails details) {
System.out.println("Log in!!");
}
};
public abstract void send(EmailDetails details);
}
public void test(String[] args) {
Email.WELCOME.send(new EmailDetails());
Email.LOGIN.send(new EmailDetails());
}
You will generally find that many of the fields are common to all uses.

Related

Design pattern for transforming the fields of a Java Object

I have a class:
#Getter
#Setter
public class Message {
private String sender;
private Set<String> receivers;
private String text;
}
The Message class can be extended by EmailMessage and SMSMessage having their own additional fields.
There are 2 services - EmailService and SMSService.
They both do the following operations:
Take the message object which contains sender and receiver user ids.
EmailService calls another service to transform the user ids to email ids. SMSService does the same to transform the user ids to phone numbers.
The Message object should be transformed to EmailMessage and SMSMEssage in their respective services.
Send the EmailMessage and SMSMessage.
I've been going through many design patterns to solve this problem. But I didn't find any such pattern to transform the fields of an object and/or convert the parent object to a child object.
The only design patterns that come close are Strategy and Decorator.
I'm using Strategy Pattern for using either EmailService or SMSService at runtime. It is solving just one part of my problem. Will Decorator Pattern help for solving the other?
Edit: Adding the current implementation
public abstract class AbstractMessageService<T extends Message> {
#KafkaHandler(isDefault = true)
public final void consume(Message message) {
T convertedMessage = getMessageConverterStrategy().convert(message);
send(convertedNotificationMessage);
}
protected abstract void send(T message) throws Exception;
protected abstract MessageConverterStrategy getMessageConverterStrategy();
}
#KafkaListener(
topics = "topicName",
groupId = "email-group")
public class EmailService extends AbstractMessageService<EmailMessage> {
#Override
protected void send(EmailMessage message) {
// Some logic to send email.
}
#Override
protected MessageConverterStrategy getMessageConverterStrategy() {
return new EmailMessageConverterStrategy();
}
}
#KafkaListener(
topics = "topicName",
groupId = "sms-group")
public class SMSService extends AbstractMessageService<SMSMessage> {
#Override
protected void send(SMSMessage message) {
// Some logic to send sms.
}
#Override
protected MessageConverterStrategy getMessageConverterStrategy() {
return new SMSMessageConverterStrategy();
}
}
public interface MessageConverterStrategy<T extends Message> {
T convert(Message message);
}
In the SMSMessageConverterStrategy and EmailMessageConverterStrategy, I want to use other design pattern to do the conversion of Message to SMSMessage and EmailMessage respectively.
Because you have to convert almost everything, I think Message and Email and SMS are not related. I think you should use Factory method like this:
public class Test {
public static void main(String[] args) throws Exception {
Message m = new Message();
Email email = Email.from(m);
EmailService.sendMail(email);
}
}
class Message {
private String sender;
private Set<String> receivers;
private String text;
}
class Email {
private String senderMailId;
private String text;
private Set<String> receiverMailIds;
//make it private
private Email() {
}
public static Email from(Message m) {
Email email = new Email();
email.senderMailId = ""; //call MappingService.toEmailId(m.getSender());
//do rest of the conversion and processing
return email;
}
}
class EmailService {
public static void sendMail(Email e) {
//send the mail
}
}
I would suggest the use of Factory method pattern.
A MessageService which would be implemented by SmsService and EmailService.
interface MessageService {
Message transform(Message message);
}
class SmsService implements MessageService {
#Override
SmsMessage transform(Message message) {
// do appropriate transformation and return.
}
}
class EmailService implements MessageService {
#Override
EmailMessage transform(Message message) {
// do appropriate transformation and return.
}
}
Then use a factory to create the appropriate service. (Assuming an enum MessageType):
public class MessageServiceFactory {
public MessageService getService(Message m, MessageType type){
switch(type) {
case SMS:
return new SmsService(m);
case EMAIL:
return new EmailService(m);
default:
// throw some exception.
}
}
}
Then to do the actual transformation:
Message convertMessage(Message m, MessageType type) {
return new MessageServiceFactory().getService(m, type)
.transform();
}

What's a good way to store class properties and load at run time?

I have a messaging producer (RabbitMQ) and depending on what kind of message i have to send, i need to change the routing key and exchange at runtime.
Given this i'd implemented a strategy to load each class with specific properties, but it's not appear a good solution.
For example:
public class MyProducerStrategy1 extends RabbitMessagingProducer {
private static final String ROUTING_KEY = "order1";
private static final String EXCHANGE = "myexchange1";
#Override
String getRoutingKey() {
return ROUTING_KEY;
}
#Override
String getExchange() {
return EXCHANGE;
}
#Override
public void sendMessage(Message message) {
super.sendMessage(message);
}
}
public class MyProducerStrategy2 extends RabbitMessagingProducer {
private static final String ROUTING_KEY = "fullfilment";
private static final String EXCHANGE = "myexchange2";
#Override
String getRoutingKey() {
return ROUTING_KEY;
}
#Override
String getExchange() {
return EXCHANGE;
}
#Override
public void sendMessage(Message message) {
super.sendMessage(message);
}
}
public abstract class RabbitMessagingProducer implements MessagingProducerStrategy {
#Autowired
private RabbitTemplate rabbitTemplate;
abstract String getRoutingKey();
abstract String getExchange();
#Override
public void sendMessage(Message message) {
rabbitTemplate.convertAndSend(getExchange(), getRoutingKey(), message);
}
}
Does it make sense? or there's another approach to load there properties and have maybe one class?
Do not create multiple class for this scenario.
load the files from a property file based on the message.
Another option is to create a static map of values with message types as the key and routing key as the value. Fetch the values from the map based on the message type.

Inheritance in Java (design pattern)

I'm refactoring some code, abstracting functionality from a subclass to a helper class, but I found that I need methods from the superclass in the helper class.
I was wondering if there is a design pattern that can help me to do this. Or any other suggestions.
public class Notification(){
public void printMessage(String k, String str){
//Some code
}
}
public class NotificationImpl1 extends Notification(){
ErrorHelper helper = new ErrorHelper();
helper.showMessage("test");
}
public class ErrorHelper(){
public void showMessage(String msg){
// need to call printMessage() here
}
}
Thanks in advance.
public class ErrorHelper(){
Notification notification = null;
public ErrorHelper(Notification notification){
this.notification = notification;
}
public void showMessage(String k_str, String msg){
this.notification.printMessage(k_str, msg);
// need to call printMessage() here
}
}
public class Notification(){
public void printMessage(String k, String str){
//Some code
}
}
public class NotificationImpl1 extends Notification(){
public void method1() {
ErrorHelper helper = new ErrorHelper();
helper.showMessage("test", this);
}
}
public class ErrorHelper() {
public void showMessage(String msg, Notification notification){
// Change msg to necessary 2 parameters.
String k = getK(msg);
String str = getStr(msg);
notification.printMessage(k, str);
}
}

Strategy pattern with inner enum

I'm trying to get rid of big switch statement from my code and I thought that Strategy pattern based on my existing enum would be nice. The concept is like:
public class MyStrategy {
public MyStrategy() {
Option.Option1.setMethodToExecute(this::action1);
Option.Option2.setMethodToExecute(this::action2);
}
public void executeChoosenMethod(int i) {
Option.values()[i].execute();
// instead of
// switch(convertItoOption()) {
// case Option1:...
// case Option2:...
// }
}
private void action1() {
System.out.println("action1");
}
private void action2() {
System.out.println("action2");
}
private enum Option {
Option1, Option2;
private InvokeAction methodToExecute;
public void setMethodToExecute(InvokeAction methodToExecute) {
this.methodToExecute = methodToExecute;
}
public void execute() {
methodToExecute.execute();
}
}
#FunctionalInterface
private interface InvokeAction {
void execute();
}
}
so I can use it like:
public class StrategyTest {
public static void main(String[] args) {
MyStrategy strategy = new MyStrategy();
//user choose 0 or 1
strategy.executeChoosenMethod(0);
strategy.executeChoosenMethod(1);
}
}
but I don't like this part with Option.Option1.setMethodToExecute(this::action1); since my enum has more and more options and I would like to have all of this inside enum. What would be perfect is something like this:
public class MyStrategy {
public void executeChoosenMethod(int i) {
Option.values()[i].execute();
}
private void action1() {
System.out.println("action1");
}
private void action2() {
System.out.println("action2");
}
private enum Option {
Option1(MyStrategy.this::action1),
Option2(MyStrategy.this::action2);
private InvokeAction methodToExecute;
private Option(InvokeAction method) {
methodToExecute = method;
}
public void execute() {
methodToExecute.execute();
}
}
#FunctionalInterface
private interface InvokeAction {
void execute();
}
}
but this is impossible since enum is static and I don't have access to enclosing instance by MyStrategy.this. I need enum, because I have set of options and it is convenient to use methods like values() or valueOf(), but what I would like to have is single line invoke instead of growing switch.
Do you have any ideas how to achieve sometghing like this or is there any workaround to make this enum constructor call possible Option1(MyStrategy.this::action1) ?
With enums you could implement it like this:
public class MyStrategy {
public void executeChoosenMethod(int i) {
Option.values()[i].execute(this);
}
private void action1() {
System.out.println("action1");
}
private void action2() {
System.out.println("action2");
}
private enum Option {
Option1(MyStrategy::action1),
Option2(MyStrategy::action2);
private InvokeAction methodToExecute;
private Option(InvokeAction method) {
methodToExecute = method;
}
public void execute(MyStrategy s) {
methodToExecute.execute(s);
}
}
#FunctionalInterface
private interface InvokeAction {
void execute(MyStrategy s);
}
}
This uses the fact the with lambdas you can make method references to arbitrary instance methods and call them on a specific instance by passing in the instance as first parameter.
you're right. This isn't possible with enum. But why not just use a good old class:
public class MyStrategy {
public MyStrategy() {
buildUp();
}
public void executeChoosenMethod(int i) {
actions.get(i).execute();
}
private void action1() {
System.out.println("action1");
}
private void action2() {
System.out.println("action2");
}
private List<InvokeAction> actions = new ArrayList<>();
private void buildUp() {
actions.add(this::action1);
actions.add(this::action2);
}
#FunctionalInterface
private interface InvokeAction {
void execute();
}
}

Storing Methods in an Enum? [duplicate]

This question already has an answer here:
Methods in Enums [duplicate]
(1 answer)
Closed 8 years ago.
Right now, I have an enum for a variety of values, and I was wondering if there is any way I would be able to store a method in an enum. For example:
public enum myEnum{
one("first", callFirstMethod),
two("second", callSecondMethod),
three("last", callThirdMethod);
public String message;
public Method met;
myEnum(String m, Method meth){
message = m;
met = meth;
}
}
public class myMethods{
public void callFirstMethod(){
System.out.println("First!");
}
public void callSecondMethod(){
System.out.println("Second!");
}
public void callThirdMethod(){
System.out.println("Third!");
}
}
Then by using something like:
Method method = myEnum.one.callFirstMethod();
To call the method. Is something like this possible? I've tried playing around/looking around on google, and nothing is really turning up. Thank you for the help!
Use an interface and have the interface instance as the second enum parameter, or give it an abstract method that is implemented in the instance. For instance:
enum MyEnum {
ONE("first", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("First!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, first!");
}
},
TWO("second", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("Second!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, second!");
}
},
THREE("last", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("Third!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, third!");
}
};
private String message;
private MyInterface myType;
private MyEnum(String m, MyInterface myType) {
message = m;
this.myType = myType;
}
public String getMessage() {
return message;
}
public MyInterface getMyType() {
return myType;
}
public void enumMethod() {
System.out.println(message);
}
public abstract void abstractEnumMethod();
}
interface MyInterface {
void commonMethod();
}
The answer all depends on what it's you want to achieve. For example, you could provide a common method within you enum and inspect the instance of the enum calling it...
public class TestEnum {
public static void main(String[] args) {
MyEnum.ONE.doStuff();
MyEnum.TWO.doStuff();
MyEnum.THREE.doStuff();
}
public enum MyEnum {
ONE("first"),
TWO("second"),
THREE("last");
public String message;
MyEnum(String m) {
message = m;
}
public void doStuff() {
System.out.println(name());
if (ONE.equals(this)) {
System.out.println("...Do stuff for one");
} else if (TWO.equals(this)) {
System.out.println("...Do stuff for two");
} else if (THREE.equals(this)) {
System.out.println("...Do stuff for three");
}
}
}
}
Which outputs...
one
...Do stuff for one
two
...Do stuff for two
three
...Do stuff for three

Categories