java在这里如何同时遵守“组合优先于继承”和DRY原则?
认为有一个简单的用例,父类具有子类,这些类具有共同的属性,例如:类动物,其名称为:
public class abstract Animal{
protected String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
abstract void printInfo();
}
和子类:
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");
}
}
根据Prefer composition over inheritance?和https://softwareengineering.stackexchange.com/questions/162643/why-is-clean-code-suggesting-avoiding-protected-variables,应该避免继承和保护变量,因此我将Animal修改为一个接口:
public interface Animal{
void setName(String name);
String getName();
void printInfo();
}
但是当移动类属性时,噩梦就来了:
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");
}
}
其中包含以下代码:
private String name;
@Override
public void setName(String name){
this.name=name;
}
@Override
public String getName(){
return name;
}
需要复制并粘贴到每个类中。此外,如果还有一个属性需要添加,例如:weight,我需要手动更新Animal和每个子类
我的问题是,这是否违反了干燥原则?如果是这样的话,有没有方法重构原始代码以避免继承和受保护的变量,同时也遵守DRY原则,这样我就不需要复制和粘贴关于公共属性的代码到每个子类中
(或者原版已经可以了?)
# 1 楼答案
作为变量,为了避免在Cat/Dog类中复制粘贴'name'变量,您可以使用单独的类来处理名称。例如:
# 2 楼答案
在你的第二种方式中,你不使用构图
在子类中实现所有抽象方法。这是不同的
这里您遇到了一个复制问题,因为您没有一个抽象的骨架类作为所有具体类的基类
这确实是一件截然不同的事情
事实上,“偏好组合而非继承”仅适用于非为继承而设计的类
抽象类是为继承而设计的:它是抽象的,并且有一个抽象方法
您使用继承的第一种方式是有意义的。 因此,在这种情况下,良好的实践是使用继承,它也允许尊重干式原则
对于不是为继承而设计的类,应该支持组合,在这种情况下,您必须在composer类中包装/组合该类
# 3 楼答案
继承是可以的,只要您不强迫用户在他们需要一个接口时使用它。Java的
List<T>
和AbstractList<T>
提供了一个很好的例子:如果需要使用部分共享实现,那么继承抽象类;如果没有,请实现接口protected String name
字段也可以设置为private
,从而消除了受保护变量的使用以下是该方法如何适用于您的类层次结构: