如何通过使用超类来减少代码?

Jax*_*ler 39 java inheritance subclass superclass

我想重构一些目前由超类和两个子类组成的代码.

这些是我的课程:

public class Animal {
    int a;
    int b;
    int c;
}

public class Dog extends Animal {
    int d;
    int e;
}

public class Cat extends Animal {
    int f; 
    int g;
}
Run Code Online (Sandbox Code Playgroud)

这是我目前的代码:

ArrayList<Animal> listAnimal = new ArrayList<>();

if (condition) {
    Dog dog = new Dog();
    dog.setA(..);
    dog.setB(..);
    dog.setC(..);
    dog.setD(..);
    dog.setE(..);   
    listAnimal.add(dog);

} else {
    Cat cat = new Cat();
    cat.setA(..);
    cat.setB(..);
    cat.setC(..);
    cat.setF(..);
    cat.setG(..);
    listAnimal.add(cat);
}
Run Code Online (Sandbox Code Playgroud)

如何重构有关公共属性的代码?

我想要这样的东西:

Animal animal = new Animal();
animal.setA(..);
animal.setB(..);
animal.setC(..);

if (condition) {
    Dog anim = (Dog) animal; //I know it doesn't work
    anim.setD(..);
    anim.setE(..);  
} else {
    Cat anim = (Cat) animal; //I know it doesn't work
    anim.setF(..);
    anim.setG(..);
}

listAnimal.add(anim);
Run Code Online (Sandbox Code Playgroud)

sla*_*dan 37

你有一个变量类型的想法Animal是好的.但是你还必须确保使用正确的构造函数:

Animal animal; // define a variable for whatever animal we will create

if (condition) {
    Dog dog = new Dog(); // create a new Dog using the Dog constructor
    dog.setD(..);
    dog.setE(..);  
    animal = dog; // let both variables, animal and dog point to the new dog
} else {
    Cat cat = new Cat(); 
    cat.setF(..);
    cat.setG(..);
    animal = cat;
}

animal.setA(..); // modify either cat or dog using the animal methods
animal.setB(..);
animal.setC(..);

listAnimal.add(animal);
Run Code Online (Sandbox Code Playgroud)

提示:如果动物总是猫或狗考虑制作动物abstract.然后编译器会在您尝试时自动发出警告new Animal().


And*_*lko 15

构建猫或狗的过程很复杂,因为涉及很多领域.对于构建器模式来说,这是一个很好的例子.

我的想法是为每种类型编写一个构建器并组织它们之间的关系.它可以是组合或继承.

  • AnimalBuilder构建一个通用Animal对象和管理a,b,c领域
  • CatBuilder需要一个AnimalBuilder(或延伸它),并继续建立一个Cat对象管理f,g字段
  • DogBuilder需要一个AnimalBuilder(或延伸它),并继续建立一个Dog对象管理d,e字段

如果您不想创建构建器,请考虑为每个子类引入一个具有有意义名称的静态工厂方法:

Animal animal = condition ? Dog.withDE(4, 5) : Cat.withFG(6, 7);
// populate animal's a, b, c
listAnimal.add(animal);
Run Code Online (Sandbox Code Playgroud)

它将简化构造并使其更简洁,更易读.


Tal*_*dar 11

回答

一种方法是在类中添加适当的构造函数.往下看:

public class Animal {
   int a, b, c; 

   public Animal(int a, int b, int c) {
      this.a = a;
      this.b = b;
      this.c = c;
   } 
}

public class Dog extends Animal {
   int d, e; 

   public Dog(int a, int b, int c, int d, int e) {
      super(a, b, c);
      this.d = d;
      this.e = e;
   } 
} 

public class Cat extends Animal {
   int f, g; 

   public Cat(int a, int b, int c, int f, int g) {
      super(a, b, c);
      this.f = f;
      this.g = g;
   } 
}
Run Code Online (Sandbox Code Playgroud)

现在,要实例化对象,您可以执行以下操作:

ArrayList<Animal> listAnimal = new ArrayList();

//sample values
int a = 10;
int b = 5;
int c = 20;

if(condition) {
   listAnimal.add(new Dog(a, b, c, 9, 11));
   //created and added a dog with e = 9 and f = 11
} 
else {
   listAnimal.add(new Cat(a, b, c, 2, 6));
   //created and added a cat with f = 2 and g = 6
} 
Run Code Online (Sandbox Code Playgroud)

这是我在这种情况下使用的方法.它通过避免大量的"设置"方法使代码更清晰,更可读.注意,这super()是对超类'(Animal在本例中)构造函数的调用.




奖金

如果您不打算创建该类的实例Animal,则应将其声明为abstract.抽象类不能实例化,但可以是子类,可以包含抽象方法.声明这些方法没有正文,这意味着所有子类都必须提供它们自己的实现.这是一个例子:

public abstract class Animal {
   //...  

   //all animals must eat, but each animal has its own eating behaviour
   public abstract void eat();
} 

public class Dog {
   //... 

   @Override
   public void eat() {
     //describe the eating behaviour for dogs
   } 
}
Run Code Online (Sandbox Code Playgroud)

现在你可以召集eat()任何动物!在前面的示例中,使用动物列表,您可以执行以下操作:

for(Animal animal: listAnimal) {
   animal.eat();
} 
Run Code Online (Sandbox Code Playgroud)

  • 像`Dog(int a,int b,int c,int d,int e)这样的构造函数吓到了我 (3认同)