Reputation: 816
I studied about SOLID Principle and created a question for me about it.
you suppose that we need a Tea
Object in Mug
class, now is this better than create a instance from Tea
in Mug
class or pass from outside through Constructor
or setter
method.
which on is true?
example:
class Mug {
private Tea tea;
public Mug(){
this.tea = new Tea();
}
public boolean isFull(){
return this.tea.value != 10;
}
}
or
class Mug {
private Tea tea;
public Mug(Tea tea){
this.tea = tea;
}
// public void setTea(Tea tea){
// this.tea = tea;
// }
public boolean isFull(){
return this.team.value != 10;
}
}
use:
public class Test {
static void main(String[] args){
Mug mug = new Mug();
//or
Mug mug = new Mug(new Tea());
}
}
which one is better?
NOTE: Suppose that Mug
support only Tea
object in our program.
Upvotes: 2
Views: 187
Reputation: 54791
I would use the second one where possible, injecting a classes dependencies, take this example where the Tea
constructor requires more information:
class Mug {
private Tea tea;
public Mug(int temperature) {
this.tea = new Tea(temperature);
}
public boolean isFull() {
return tea.value != 10;
}
}
See how ugly that is that Mug
's constructor now needs information only used by Tea
's constructor.
But as it stands I would say that neither of your examples violates any SOLID principle.
There is nothing that says you can't create a new object inside another and nothing that says you must create abstractions.
Here would be a real violation in this area:
class Mug { // VIOLATION
private Tea tea;
private Coffee coffee;
public Mug(boolean tea) {
if (tea) {
this.tea = new Tea();
} else {
this.coffee = new Coffee();
}
}
public boolean isFull() {
return tea.value != 10 || coffee.value != 10;
}
}
The class depends upon multiple similar classes. Compare to:
class Mug {
private Liquid liquid;
public Mug(Liquid liquid) {
this.liquid = liquid;
}
public boolean isFull() {
return liquid.getVolume() != 10;
}
}
interface Liquid {
int getVolume();
}
class Tea implements Liquid {
private int volume;
@Override
public int getVolume() {
return volume;
}
}
class Coffee implements Liquid {
private int volume;
@Override
public int getVolume() {
return volume;
}
}
But as you only have one thing that can go in a Mug
there is no violation and no need for an abstraction. In general, never write any code that doesn't solve a problem.
And never create an abstraction with a name like ITea
. In such a case either the concrete class name is not specific enough, or the abstraction name is not general enough.
Upvotes: 0
Reputation: 5316
Both of your cases violate SOLID.
Your each concrete implementation (concrete class) should only be dependent upon Abstractions. in your case Tea is not an abstraction. Mug has tight coupling with Tea. Below is a possible way to code it.
public interface ITea{
//tea related methods which you think should be exposed to outside world. Also all implementation of ITea must support these method (L in SOLID)
}
public class Tea implements ITea{
// Implement the contract methods from ITea
}
public class Mug {
private ITea tea;
// Have constructor or setter to inject concrete implementation. Setter will provide you capability to modify behavioral at run time.
}
EDIT: 1. If we are sure there is only one possible implementation Of tea. Then also interface is better as concrete implementations are hard to mock and hence makes unit testing is difficult.
If a case is added you have to modify existing code and in case you forget to add a case somewhere it leads to unexpected errors. (It violates OCP. Instead of enums put logic in specific implementation, have common interface and specific implementation). Also if we implement the case specific logic in individual instances of enum then the enum file will become gigantic. Instead if we have specific logic in individual concrete classes implementing common interface makes the user code easy as it can be injected with concrete classes in a polymorphic way.
p.s. this answer is about following the principles and it's not always possible to do so. It's fine to violate the principle but we must know that we are violating it, and have a very good reason to do so.
Upvotes: 1