Assume an initial scenario, following which I would be the modified problematic case.
interface Logger {
log() { }
}
class LogFile extends Logger {
log() { // log to file }
}
class LogDB extends Logger {
log() { // insert log into DB }
}
Now LogDB changes into something like:
class LogDB {
logMySQL() { };
logMongo() { };
}
How can this change be incorporated into LogDB while I still want it to fit into Logger interface ?
I think it's better to make two subclasses of the LogDB class - one for dealing with MongoDB and one for MySQL.
class LogMongoDB extends LogDB {
#Override
log() {
//persist the log in MongoDB
}
}
class LogMySQL extends LogDB {
#Override
log() {
//persist the log in MySQL
}
}
If LogDB needs to implement Log, but must also do some customized logging, add a function that does the generic logging activity, as required by the interface, and call it from each customized version (or vice-versa, depending on your needs):
public void log() {
//Common logging stuff here
}
public void logDB() {
//Database-specific logging here...
log();
}
public void logMongo() {
//Mongo-specific logging here...
log();
}
But as stated by #kocko, you seem to be mashing two types of logging into one object, which is why you're asking the question in the first place. Split it up as he suggests, then you won't have this problem to begin with.
I'd do it differently, not with inheritance, but with composition.
interface Logger {
log(String message) { }
}
class LogFile extends Logger {
public LogFile(File file) {}
log(String message) { /* log to file */ }
}
class LogDB extends Logger {
private DBLogConf dbConf;
private DBAbstractionLayer dbal;
public LogDB(IDBLogConf dbConf, IDBAbstractionLayer dbal) {
this.dbConf = dbConf;
this.dbal = dbal;
}
log(String message) {
List<String> fields = new ArrayList<String>();
fields.add(dbConf.getLogField());
List<String> values = new ArrayList<String>();
fields.add(message);
dbal.insert(dbConf.getContainer(), fields, values);
}
}
interface IDBLogConf {
public String getContainer(); // table or document
public String getLogField();
}
class DBLogConf implements IDBLogConf { /* ... */ }
interface IDBAbstractionLayer {
public void insert(String container, List<String> fields, List<String> values) {
// ...
}
// other methods
}
class JDBCAbstractionLayer implements IDBAbstractionLayer {
private Connection conn;
public JDBCAbstractionLayer(Connection conn) {
this.conn = conn;
}
public function insert(...) { /* ... */}
}
abstract class NoSQLAbstractionLayer implements IDBAbstractionLayer {
// ...
}
class MongoAbstractionLayer extends NoSQLAbstractionLayer {
// ...
}
Putting this all toghether:
IDBConf dbConf = new DBConf('log_table', 'details');
IDBAbstractionLayer dbal = new JDBCAbstractionLayer(/* some JDBC connection, */);
Logger dbLogger = new LogDb(dbConf, dbal);
dbLogger.log("Something");
Logger fileLlogger = new LogFile(new File('/var/log/my_log'));
fileLogger.log("Something");
However this seems more complex than the above examples, this implementation does not violate SRP and avoids code duplication.
Related
I hope you're doing well, I have a doubt when I try to create a method that can validate some business rules.
In this case, I have a class
public class ValidationUtils {
final List<CreditValidations> creditValidations;
public ValidationUtils(){
creditValidations = Arrays.asList(
new ValidateAge(),
new ValidateSalary()
);
}
public ValidationRs passAllValidations(Client client){
final var validationsFailed = new ArrayList<String>();
boolean validationResult = false;
for (CreditValidations creditValidationClasses : creditValidations){
validationResult = Boolean.logicalXor(creditValidationClasses .validate(client,validationsFailed),
validationResult);
}
final var rs = new ValidationRs();
rs.setSuccessfulValidations(validationResult);
rs.setValidationsFailed(validationsFailed);
return rs;
}
}
this class has a method called "passAllValidations" That method can evaluate each CreditValidation implementation and join their results, Using this code I don't need to create more methods when I have a new validation, only extends the abstraction and create the new Validation class and inject it in the ValidationUtils constructor.
the abstraction and implementation of CreditValidations look like
public abstract class CreditValidations {
protected final String errorCode;
protected CreditValidations(final String errorCode) {
this.errorCode = errorCode;
}
protected abstract boolean validate(final Client client,final List<String> validationsFailed);
protected boolean evaluateValidation(boolean validationResult, List<String> validationsFailed){
if (!validationResult){
setCode(validationsFailed);
}
return validationResult;
}
protected String getErrorCode() {
return this.errorCode;
}
protected void setCode(List<String> failedValidations) {
failedValidations.add(errorCode);
}
}
public class ValidateAge extends CreditValidations {
public ValidateAge() {
super(CreditValidationErrorEnum.ERROR_VALIDATING_AGE.getCode());
}
#Override
public boolean validate(final Client client, List<String> validationsFailed) {
return this.evaluateValidation(client.getAge() >= 18,validationsFailed);
}
}
in summary, my question is referring to the dependency injection in the class ValidationUtils, I don't know if it way is correct or if Spring Framework has some things that help me to inject all of the CreditValidation implementations and avoid using Array.asList(new NewValidationClass()) or another design pattern which can help.
Thanks in advance.
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 have to write a test for the login dialog that shows up on my website, but there are two, and only two access points for this login dialog. Ideally, my page objects should reflect the restricted access to this login dialog.
When you clickLogin on the Header, a LoginDialog pops up
When you postComment on an Article, and you aren't logged in (and we'll assume you aren't for simplicity), a LoginDialog pops up.
Here's what it looks like in code:
new LoginDialog().login(); // shouldn't be allowed
new Header().clickLogin().login(); // should be allowed
new Article().postComment().login() // should be allowed
I came up with a method for getting around this. LoginDialog only has two constructors, which both take in an object that can only be constructed in either Header or Article.
public class LoginDialogTest extends WebTest {
#Test
public void testLoginDialogFromHeader {
new HomePage().loadPage();
new Header().clickLogin().login();
verifyLoggedIn();
}
#Test
public void testLoginDialogFromArticleComment {
new ArticlePage(42).loadPage(); // Load an article with id=42
new Article().postComment().login();
verifyLoggedIn();
}
}
public class LoginDialog {
public LoginDialog(Article.CommentButton commentButton) {
}
public LoginDialog(Header.LoginButton loginButton) {
}
public void login() {
}
}
public class Article {
public class CommentButton {
private CommentButton() {
}
public LoginDialog click() {
return new LoginDialog(this);
}
}
public LoginDialog postComment() {
return new CommentButton().click();
}
}
public class Header {
public class LoginButton {
public LoginDialog click() {
return new LoginDialog(this);
}
}
public LoginDialog clickLogin() {
return new LoginButton().click();
}
}
My question is whether or not this is an existing pattern, and if it is, what is its name? If it isn't, what would be a good name for it?
I think this would be a foolproof way of making sure only Header or Article could create a LoginDialog:
public class LoginDialog {
private LoginDialog() {
... code to construct
}
public interface Constructor {
LoginDialog newLoginDialog();
}
private static class ConstructorImpl implements Constructor {
public LoginDialog newLoginDialog() {
return new LoginDialog();
}
}
private static ConstructorImpl constructor;
static {
constructor = new ConstructorImpl();
Header.provideLoginDialogConstructor(constructor);
Article.provideLoginDialogConstructor(constructor);
}
}
and in Header and Article, provide a public provideLoginDialogConstructor method:
private static LoginDialog.Constructor constructor;
public static void provideLoginDialogConstructor(LoginDialog.Constructor constructor) {
Header.constructor = constructor; // or Article.constructor
}
and when those classes need to construct a LoginDialog:
if (!loggedIn()) {
return constructor.newLoginDialog();
} else {
return null;
}
Since the LoginDialog class decides what classes get to have its private object to construct a LoginDialog, there should be no way for another class to obtain the ability to construct one using normal means [there might be tricky ways using reflection].
Note: I haven't tested this.
I have an abstract class Action with children like SendMessageAction.
I would like to run these actions in a service but how could I force implementation of each child ?
For example I would like to implement an abstract method : void run(Action action)
and methods "run" for each possible Action with an error if some methods are missing.
Any idea ?
Something like below should help you to get started. Happy coding!
Action.java
public abstract class Action {
protected abstract void runAction();
}
MessageSenderAction.java
public class MessageSenderAction extends Action {
public void runAction() {
//send message
}
}
SomeOtherAction.java
public class SomeOtherAction extends Action {
public void runAction() {
//do something else
}
}
ActionHandler.java
public class ActionHandler {
private final static ActionHandler INSTANCE = new ActionHandler();
private ActionHandler() {}
public static ActionHandler getInstance() {
return INSTANCE;
}
private List<Action> allActions = new ArrayList<Action>();
public void addAction(Action action) {
allActions.add(action);
}
public void runAllActions() {
for(Action action: allActions) {
//just to handle exception if there is any. Not to hamper other actions in case of any failures
try {
action.runAction();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
ActionDemo.java
public class ActionDemo {
public static void main(String... args) {
ActionHandler actionHandler = ActionHandler.getInstance();
Action msgSenderAction = new MessageSenderAction();
Action someOtherAction = new SomeOtherAction();
actionHandler.addAction(msgSenderAction);
actionHandler.addAction(someOtherAction);
actionHandler.runAllActions();
}
}
I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}