Cool, let's play a little with this code!
First of all let's consider this class:
/**
* I'm a Service (?) bound to a given name that returns a fixed string whenever asked to.
*/
public class HelloService {
// the service is bound to a given fixed name
String name;
// to create an instance of this service you need to know the name beforehand
HelloService(String name){
this.name = name;
}
// this always returns the same string
public String getHello() {
// creates a new instance of this class every time
Decorator decorator = new Decorator();
String full = decorator.bar
+ this.name
+ Footer.add(this.name);
return full;
}
}
IDK it doesn't seem nor SOLID nor KISS:
- do you really need a class to concat three strings in a fixed way?
- do you really want to instantiate an object for each person you want to say hello to? how is this simple?
- what SOLID principles does this fallow?
So what about something like this?
/**
* I'm a class that greets people.
*/
public class Greeter {
// I need a decorator and a footer to work properly
// ...so if someone extends me it'd probably need them too!
protected Decorator decorator;
protected Footer footer;
// please give me what I need when making a new instance
public Greeter(Decorator decorator, Footer footer) {
this.decorator = decorator;
this.footer = footer;
}
// this is what I do: I greet people based on their name.
public final String greet(String name) {
return this.decorator.get() + name + this.footer.get(this.name);
}
}
Ok let's think at what this class says (besides the comments):
- it's a class that greets people
- it needs a decorator and a footer to work properly
- its concern is to greet people based on their name
- the piece of logic it holds is that a "greeting" is in the form
decorator + name + footer
. This is what this class enforces, the business logic it holds is "I want to state and fix the concept that a greeting has this specific pattern".
- you can extend this with any other class that adds some other kind of greetings, but it will always have a
greet
method that enforces the original logic
- you can make
Decorator
and Footer
interfaces so that you can have multiple implementations for different kinds of greetings and never change this class
- when you read it it's stupid simple like "ok given this and that, I concat the strings and that's all". No worries about
Decorator
or Footer
being interfaces, just one instance, no worries about how to instantiate those other classes etc.
So in the end I think that if you keep it simple you can also be SOLID and vice-versa. The hard part is not trying to fallow various principles, but trying to understand what your code "says":
- What do I represent?
- What is my concern? What logic I'm enforcing?
- What do I need to do my job?
- How can my job be useful in different scenarios?
Once you have a clear understanding of that, you can check out all the principles to see if what you wrote does comply (and if it really needs to).
Some usage code examples with the above class:
public interface Decorator {
public String get();
}
public interface Footer {
public String get(String name);
}
public class BasicDecorator implements Decorator {
public String get() {
return "Hi, ";
}
}
public class RudeDecorator implements Decorator {
public String get() {
return "Oh no! ";
}
}
public class PoliteDecorator implements Decorator {
public String get() {
return "Thank goodness! ";
}
}
public class BasicFooter implements Footer {
public String get(String name) {
if(name.length > 5) return "... welcome!";
else return "... how are you?";
}
}
Footer basicFooter = new BasicFooter();
Greeter politeGreeter = new Greeter(new PoliteDecorator(), basicFooter);
politeGreeter.greet("Carlo");
// returns "Thank goodness! Carlo... how are you?"
public class TitleGreeter extends Greeter {
public TitleGreeter(Decorator decorator, Footer footer) {
super(decorator, footer);
}
// see here I can add other logic like "a title is some string that goes before the name.
// but it will never change the logic enforced by the parent class of what a "greeting" is.
public String titleGreet(String title, String name) {
return this.greet(title + " " + name);
}
}
Greeter rudeTitleGreeter = new TitleGreeter(new RudeDecorator(), basicFooter);
rudeTitleGreeter.titleGreet("Mr.", "Moretti");
// returns "Oh no! Mr. Moretti... welcome!"