Consider there is a simple use case, a parent class with child classes which has common properties, eg: class Animal which has a name:
public class abstract Animal{
protected String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
abstract void printInfo();
}
and subclass :
public class Cat extends Animal{
@Override
public void printInfo(){
System.out.println("I'm a cat");
}
}
public class Dog extends Animal{
@Override
public void printInfo(){
System.out.println("I'm a dog");
}
}
according to Prefer composition over inheritance? and https://softwareengineering.stackexchange.com/questions/162643/why-is-clean-code-suggesting-avoiding-protected-variables, inheritance and protected variables should be avoid, so I modified Animal into an interface:
public interface Animal{
void setName(String name);
String getName();
void printInfo();
}
but the nightmare comes when moving the class property:
public class Cat implements Animal{
private String name;
@Override
public void setName(String name){
this.name=name;
}
@Override
public String getName(){
return name;
}
@Override
public void printInfo(){
System.out.println("I'm a cat");
}
}
public class Dog implements Animal{
private String name;
@Override
public void setName(String name){
this.name=name;
}
@Override
public String getName(){
return name;
}
@Override
public void printInfo(){
System.out.println("I'm a dog");
}
}
which the following code:
private String name;
@Override
public void setName(String name){
this.name=name;
}
@Override
public String getName(){
return name;
}
needs to copy and paste into each class. Furthermore, if there is one more property to add, eg:weight, I need to update Animal and each subclass manually.
My question is, is it violating DRY principle? if so, is there any method to refactor the original code so that it avoids inheritance and protected variables and also obeys DRY principle at the same time, so that I don't need to copy and paste codes about common properties into each subclass?
(or is the original already fine?)
inheritance and protected variables should be avoided
Inheritance is fine, as long as you are not forcing users into using it when all they need an interface. Java's List<T>
and AbstractList<T>
provide a good example: if you need to use parts of shared implementation, inherit the abstract class; if you don't, implement the interface.
protected String name
field could be made private
, too, eliminating the use of protected variables.
Here is how the approach would work for your class hierarchy:
public interface Animal {
void setName(String name);
String getName();
void printInfo();
}
public abstract class AbstractAnimal implements Animal {
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
abstract void printInfo();
}
public class Cat extends AbstractAnimal {
@Override
public void printInfo(){
System.out.println("I'm a cat");
}
}
public class Dog extends AbstractAnimal {
@Override
public void printInfo(){
System.out.println("I'm a dog");
}
}