这里如何同时遵守“组合优于继承”和 DRY 原则?

oco*_*mfd 2 java inheritance dry composition

考虑有一个简单的用例,一个带有具有共同属性的子类的父类,例如:类 Animal 有一个名称:

public class abstract Animal{
    protected String name;
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }

    abstract void printInfo();
}
Run Code Online (Sandbox Code Playgroud)

和子类:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

根据优先组合而不是继承?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();
}
Run Code Online (Sandbox Code Playgroud)

但是在移动类属性时噩梦就来了:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

以下代码:

private String name;
@Override
public void setName(String name){
    this.name=name;
}
@Override
public String getName(){
    return name;
}
Run Code Online (Sandbox Code Playgroud)

需要复制并粘贴到每个类中。此外,如果还有一个属性要添加,例如:weight,我需要手动更新 Animal 和每个子类。

我的问题是,它是否违反了 DRY 原则?如果是这样,有没有什么方法可以重构原始代码,避免继承和保护变量,同时也遵守DRY原则,这样我就不需要将公共属性的代码复制粘贴到每个子类中?

(或者原来的已经没问题了?)

das*_*ght 5

应避免继承和受保护的变量

继承很好,只要你不强迫用户在他们需要一个界面时使用它。Java的List<T>AbstractList<T>提供了一个很好的例子:如果需要使用部分共享实现,继承抽象类;如果不这样做,请实现该接口。

protected String name也可以制作字段private,从而消除受保护变量的使用。

以下是该方法如何适用于您的类层次结构:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)