正确使用抽象方法

Properly using abstract methods

我无法理解抽象方法的概念以及如何正确使用它们。

基本上,我被指示编写一个带有抽象超类 "Alien" 和 2 个子类 "Martian and Saturner" 的代码,其中 类 存在 invade()方法应该接受外星人攻击的行星名称作为参数,而不是 return 值。

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

abstract class Alien
{
private String planet;
private String age;
private String name;
private String skinColor;
private String alienPower;

public Alien(String planet, String age, String name, String skinColor, String alienPower)
{
    this.planet=planet;
    this.age=age;
    this.name=name;
    this.skinColor=skinColor;
    this.alienPower=alienPower;
}

public abstract void invade(String planetName); 
public String toString()
{
    return name + " is from " + planet + ", is " + age + " years old, "  + " has " + skinColor + " skin, and has the ability " + alienPower ;
}   
}

class Martian extends Alien {
public Martian(String p, String a, String n, String s, String ap) {
    super(p,a,n,s,ap);
}

@Override
public void invade(String strategy, String planetName) {
    System.out.println("I am a Martian " + strategy + planetName);
}

}


class Saturner extends Alien {
public Saturner(String p, String a, String n, String s, String ap) {
    super(p,a,n,s,ap);
}

public void invade(String strategy, String planetName) {
    System.out.println("I am a Saturner " + strategy + planetName);
}
}

public class TestAlien {
public static void main(String[]args) {
    ArrayList<Alien> alienList = new ArrayList<>();
    List<String> planets = Arrays.asList(new String[] {"Earth", "June", "Mercury", "Venus", "Neptune"});
    List<String> methods = Arrays.asList(new String[] {"shooting missiles at", "polluting the water systems of", "burning", "flooding"});

    alienList.add(new Martian("Mars", "148", "Zornok", "red", "Read minds"));
    alienList.add(new Saturner("Saturn", "89", "Hookman", "pitch black ", "Go invisible"));
    alienList.add(new Martian("Mars", "18", "Guthrax", "gray", "Teleport"));
    alienList.add(new Saturner("Saturn", "300", "Lamron", "blue", "Fly\n"));
    int i = 0;

    for (Alien al : alienList) {
        System.out.println("Alien race: " + al.getClass().getName() + " || description = " + al.toString());
        al.invade(methods.get(i) al.invade(planets.get(i));
        i++;
    }

如果你的 invade() 方法应该接受一个行星,那么第一步实际上是实现一个行星类型(读作:class),然后像这样为每个物种实现 invade 方法:

@Override
void invade(Planet target) {
    //attack planet
}

为了攻击不同的行星,您需要一个可用行星列表,遍历外星人,从行星列表中随机选择一个行星(查看 java.util.Random)并在每个外星人上调用入侵方法:

Random rng = new Random();
for (Alien alien : aliens) {
    int roll = rng.nextInt(aliens.size());
    Planet target = planets.get(roll);
    alien.invade(target);
}

我认为您正在寻找这样的东西:

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

abstract class Alien {
    private String p;
    private String a;
    private String n;
    private String s;
    private String ap;

    public Alien(String p, String a, String n, String s, String ap) {
        this.p = p;
        this.a = a;
        this.n = n;
        this.s = s;
        this.ap = ap;
    }

    public abstract void invade(String planetName); 
}

class Martian extends Alien {
    public Martian(String p, String a, String n, String s, String ap) {
        super(p,a,n,s,ap);
    }

    @Override
    public void invade(String planetName) {
        System.out.println("I am a Martian invading " + planetName);
    }

}


class Saturner extends Alien {
    public Saturner(String p, String a, String n, String s, String ap) {
        super(p,a,n,s,ap);
    }

    public void invade(String planetName) {
        System.out.println("I am a Saturner invading " + planetName);
    }
}

public class TestAlien {
    public static void main(String[]args) {
        ArrayList<Alien> alienList = new ArrayList<>();
        List<String> planets = Arrays.asList(new String[] {"Earth", "June", "Mercury", "Venus", "Neptune"});

        alienList.add(new Martian("Mars", "148", "Zornok", "red", "Read minds"));
        alienList.add(new Saturner("Saturn", "89", "Hookman", "pitch black ", "Go invisible"));
        alienList.add(new Martian("Mars", "18", "Guthrax", "gray", "Teleport"));
        alienList.add(new Saturner("Saturn", "300", "Lamron", "blue", "Fly\n"));
        int i = 0;

        for (Alien al : alienList) {
            System.out.println("Alien race: " + al.getClass().getName() + " || description = " + al.toString());
            al.invade(planets.get(i));
            i++;
        }
    }
}

变化是唯一不变的,抽象什么变化。在您的情况下,每个外星人可能有不同的入侵行星的方式,这可能基于外星人所属的家庭、可用资源以及要入侵的行星类型。

Class外星人是超级class,可能不知道行星的类型(未来可能会有更多),因此也可能有许多不同种类的外星人。一个星球上的每个原住民都可能有不同的入侵行为。因此方法 invade() 最好做成 abstract

现在正如您所说,它接受要入侵的行星的名称,return 什么都没有。您可以在 Alien.java 中将其定义为抽象

public abstract void invade(String planetName);

所有子class将实施并提供具体实施。

在 driver 代码中,您可以 迭代 并可以使用行星名称调用方法 invade

Edit 如果您需要不同的 Strategy 进行入侵,那么我们需要考虑将其抽象化。您可以定义一个抽象 class InvadingStrategy 或者可以有一个接口。 这可以包括与策略相关的方法。一种这样的方法可以像下面这样

public abstract String getStrategyDescription();

您可能有不同的具体 classes(WaterSystemPollutionStrategyBombingStrategy 等),它们将提供 InvadingStrategy 定义的抽象方法的实现。现在你对 invade 方法的签名可能像

public abstract void invade(String planetName, InvadingStrategy strategy);

可以根据要入侵的星球名称调用invade方法,具体攻略objectclass。在 Alien.java 的子 class 方法实现 invade 方法时,您可以打印行星的名称以及由 [=28=104=] 编辑的字符串=].

编辑 2

下面你可以看到 classes 和界面,我尽量保持与你提供的代码相似的结构,但仍然尽量保持代码的灵活性以适应未来的变化。通过遵循良好的 OOP 原则,您可以编写易于维护和理解的简洁代码。

Alien.java

public abstract class Alien {
    // Copying it from the question, Suggestion : USE contextual meaningful names 
    public Alien(String p, String a, String n, String s, String ap) {
        // set the properties and do the necessary initialization.
    }
    public abstract void invade(String planetName, InvadingStrategy strategy);
}

外星人的子 class : Martian.java 同样地,你可以拥有外星人的各种子class

public class Martian extends Alien {
    public Martian(String p, String a, String n, String s, String ap) {
        super(p, a, n, s, ap);
    }

    @Override
    public void invade(String planetName, InvadingStrategy strategy) {
        System.out.println("I am Martian, I am going to invade " + planetName + " and My Strategy will be "
                + strategy.getStrategyDescription());
    }
}

InvadingStrategy Interface :这可以包括策略的必要方法。目前只有一种方法可以获取策略的描述。

public interface InvadingStrategy {
    String getStrategyDescription();
}

实施 InvadingStrategy 的具体 class :MissileStrategy 同样,你可以有多种策略

public class MissileStrategy implements InvadingStrategy {

    @Override
    public String getStrategyDescription() {
        return "shooting missiles at";
    }

}

另一个实施 InvadingStrategy 的具体 class:WaterSystemDestructionStrategy

public class WaterSystemDestructionStrategy implements InvadingStrategy {

    @Override
    public String getStrategyDescription() {
        return "polluting the water systems of";
    }

}

Driver代码 导入 java.util.ArrayList; 导入 java.util.Arrays; 导入 java.util.List;

public class Driver {
    public static void main(String[] args) {
        ArrayList<Alien> alienList = new ArrayList<>();
        alienList.add(new Martian("Mars", "148", "Zornok", "red", "Read minds"));
        alienList.add(new Saturner("Saturn", "89", "Hookman", "pitch black ", "Go invisible"));
        alienList.add(new Martian("Mars", "18", "Guthrax", "gray", "Teleport"));
        alienList.add(new Saturner("Saturn", "300", "Lamron", "blue", "Fly\n"));

        List<String> planets = Arrays.asList(new String[] {"Earth", "June", "Mercury", "Venus", "Neptune"});
        List<InvadingStrategy> methods = Arrays.asList(new InvadingStrategy[]{new MissileStrategy(),new WaterSystemDestructionStrategy(),new BurningStrategy(),new FloodingStrategy()});

        int i = 0;
        for(Alien alien : alienList){
            alien.invade(planets.get(i) , methods.get(i));
            i++;
        }
    }
}