这里如何同时遵守"composition over inheritance"和DRY原则呢?
How to obey "composition over inheritance" and DRY principle at the same time here?
考虑一个简单的用例,父 class 和子 class 具有共同属性,例如:class 动物,其名称为:
public class abstract Animal{
protected String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
abstract void printInfo();
}
和子class :
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? and 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();
}
但是当移动 class 属性:
时噩梦就来了
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;
}
需要复制并粘贴到每个 class。此外,如果还有一个 属性 要添加 eg:weight,我需要手动更新 Animal 和每个子 class。
我的问题是,这是否违反了DRY原则?如果是这样,有什么方法可以重构原始代码,使其避免继承和受保护的变量,同时也遵守 DRY 原则,这样我就不需要将有关公共属性的代码复制并粘贴到每个 subclass?
(或者原来的已经好了?)
inheritance and protected variables should be avoided
继承很好,只要您不强迫用户在他们需要接口时使用它。 Java的List<T>
和AbstractList<T>
提供了一个很好的例子:如果你需要使用共享实现的部分,继承抽象class;如果不这样做,请实现接口。
protected String name
字段也可以private
,消除对受保护变量的使用。
以下是该方法如何适用于您的 class 层次结构:
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");
}
}
Prefer composition over inheritance
在你的第二种方式中,你没有使用组合。
您在 subclasses 中实现所有抽象方法。哪个不一样。
在这里,您遇到了重复问题,因为您没有抽象骨架 class 作为所有具体 classes.class 的基础 class。
真是另当别论。
事实上 "Prefer composition over inheritance" 仅适用于 class 不是为继承而设计的。
您的抽象 class 是为继承而设计的:它是抽象的并且有一个抽象方法。
您使用继承的第一种方式很有意义。
所以在这种情况下,好的做法是使用继承,它也允许尊重 DRY 原则。
对于 class 不是为继承而设计的,组合应该受到青睐,在这种情况下,您必须 wrap/compose 作曲家 class 中的 class。
作为避免在 Cat/Dog class 中复制粘贴 'name' 变量的变体,您可以使用单独的 class 进行名称处理。示例:
public interface Animal {
void setName(String name);
String getName();
void printInfo();
}
public class DefaultNameHolder {
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
// Same for Dog class
public class Cat implements Animal {
private DefaultNameHolder nameHolder = new DefaultNameHolder();
@Override
public void setName(String name) {
// Delegation
nameHolder.setName(name);
}
@Override
public String getName() {
// Delegation
return nameHolder.getName();
}
@Override
public void printInfo(){
System.out.println("I'm a cat");
}
}
public class Developer implements Animal {
private String firstName;
private String lastName;
@Override
public void setName(String name) {
// Some special logic for setName()
this.firstName = name.split(" ")[0];
this.lastName = name.split(" ")[1];
}
@Override
public String getName() {
// Some special logic for getName()
return "My first name is " + firstName + ", my last name is " + lastName;
}
@Override
public void printInfo(){
System.out.println("Will code for food.");
}
}
考虑一个简单的用例,父 class 和子 class 具有共同属性,例如:class 动物,其名称为:
public class abstract Animal{
protected String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
abstract void printInfo();
}
和子class :
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? and 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();
}
但是当移动 class 属性:
时噩梦就来了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;
}
需要复制并粘贴到每个 class。此外,如果还有一个 属性 要添加 eg:weight,我需要手动更新 Animal 和每个子 class。
我的问题是,这是否违反了DRY原则?如果是这样,有什么方法可以重构原始代码,使其避免继承和受保护的变量,同时也遵守 DRY 原则,这样我就不需要将有关公共属性的代码复制并粘贴到每个 subclass?
(或者原来的已经好了?)
inheritance and protected variables should be avoided
继承很好,只要您不强迫用户在他们需要接口时使用它。 Java的List<T>
和AbstractList<T>
提供了一个很好的例子:如果你需要使用共享实现的部分,继承抽象class;如果不这样做,请实现接口。
protected String name
字段也可以private
,消除对受保护变量的使用。
以下是该方法如何适用于您的 class 层次结构:
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");
}
}
Prefer composition over inheritance
在你的第二种方式中,你没有使用组合。
您在 subclasses 中实现所有抽象方法。哪个不一样。
在这里,您遇到了重复问题,因为您没有抽象骨架 class 作为所有具体 classes.class 的基础 class。
真是另当别论。
事实上 "Prefer composition over inheritance" 仅适用于 class 不是为继承而设计的。
您的抽象 class 是为继承而设计的:它是抽象的并且有一个抽象方法。
您使用继承的第一种方式很有意义。 所以在这种情况下,好的做法是使用继承,它也允许尊重 DRY 原则。
对于 class 不是为继承而设计的,组合应该受到青睐,在这种情况下,您必须 wrap/compose 作曲家 class 中的 class。
作为避免在 Cat/Dog class 中复制粘贴 'name' 变量的变体,您可以使用单独的 class 进行名称处理。示例:
public interface Animal {
void setName(String name);
String getName();
void printInfo();
}
public class DefaultNameHolder {
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
// Same for Dog class
public class Cat implements Animal {
private DefaultNameHolder nameHolder = new DefaultNameHolder();
@Override
public void setName(String name) {
// Delegation
nameHolder.setName(name);
}
@Override
public String getName() {
// Delegation
return nameHolder.getName();
}
@Override
public void printInfo(){
System.out.println("I'm a cat");
}
}
public class Developer implements Animal {
private String firstName;
private String lastName;
@Override
public void setName(String name) {
// Some special logic for setName()
this.firstName = name.split(" ")[0];
this.lastName = name.split(" ")[1];
}
@Override
public String getName() {
// Some special logic for getName()
return "My first name is " + firstName + ", my last name is " + lastName;
}
@Override
public void printInfo(){
System.out.println("Will code for food.");
}
}