Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用抽象类并将它们作为一个实体访问,OOP设计?_Java_Oop_Design Patterns - Fatal编程技术网

Java 使用抽象类并将它们作为一个实体访问,OOP设计?

Java 使用抽象类并将它们作为一个实体访问,OOP设计?,java,oop,design-patterns,Java,Oop,Design Patterns,我不确定实现我的类的确切方式 比如说,我有棒球和篮球课,这两门课的特点各不相同,而且都扩展了体育 我的例子是: public abstract class Sports { public abstract getSport(); public abstract getCoach(); public abstract getTeamSize() { System.out.println("The size of the team is xxx.")

我不确定实现我的类的确切方式

比如说,我有棒球和篮球课,这两门课的特点各不相同,而且都扩展了体育

我的例子是:

public abstract class Sports
{
    public abstract getSport();
    public abstract getCoach();
    public abstract getTeamSize() 
    {
        System.out.println("The size of the team is xxx.");
    }
}

public class Baseball extends Sports
{
    public List<Baseballs> getBaseballs()
    {
        // Get list of another object baseballs.
    }
    // Implementation of abstract methods.
}

public class Basketball extends Sports
{
    public List<Basketballs> getBasketballs()
    {
        // Get list of another object basketballs.
    }
    // Implementation of abstract methods.
}
对于这个例子来说,棒球和篮球是如此的不同,它们没有相似的特征


但是,我会有一个未使用的棒球声明和篮球声明。

听起来像你有一个操作,你想在任何
运动
对象上执行,不管它的实际类型如何。要做到这一点,您需要在基类(可能是
abstract
)中定义它,然后在子类中包含相关的实现

例如,您应该为
Sports
提供一个方法:
protectedabstractvoidprintball()

然后在每个子类中适当地实现它。例如,在
棒球
中,您可以:

@Override
protected abstract void printBalls() {
  for(Baseball baseball: this.getBaseballs()) {
    System.out.println(baseball);
  }
}

如果我理解的话,对于不同类型的列表,您需要相同的方法。铸造并不总是一个好主意,你需要的是界面。这就像你的方法的通用“类”。接口的代码几乎相同,您可以在类中实现所需的内容,接口将根据类型选择要调用的方法。接口中的方法和类中的方法必须相同,类必须实现接口。

您的第二个代码要好得多,尽管仍然缺少一些东西,以下是我所说的代码:

    public class Sports
    {
        String sportType = "[Sport]";
        List<Basketball> basketballs;
        List<Baseball> baseballs;
        public getTeamSize() 
        {
            System.out.println("The size of the team is 10.");
        }
        public List<Basketball> getBasketballs 
        {
            return this.basketballs;
        }
        public List<Baseball> getBaseballs
        {
            return this.baseballs;
        }
    }
棒球课:

public class Basketball extends Sports {

    private int sizeOfTeam;

    public Basketball(String teamName) {
        super(teamName, 10);
        //Defaults 10 players
    }

    @Override
    public int getTeamSize() {
        return sizeOfTeam;
    }

    @Override
    public void setTeamSize(int sizeOfTeam) {
        this.sizeOfTeam = sizeOfTeam;
    }
}
public class Baseball extends Sports {

    private int sizeOfTeam;

    public Baseball() {
        super("team");
    }

    @Override
    public int getTeamSize() {
        return sizeOfTeam;
    }

    @Override
    public void setTeamSize(int sizeOfTeam) {
        this.sizeOfTeam = sizeOfTeam;
    }
}
我简化了它,虽然这是一个更好的方法,你基本上可以定义你想要的任何属性,并自动将其添加到列表中,直到程序结束。您可以选择在另一个类中创建对象(请看下面我使用的驱动程序),或者简单地将内容直接添加到Sports类本身的列表中,就像创建任意数量的运动对象一样,并将其自包含。对于棒球和篮球,我给出了两个类的例子,这些类被过分简化了,但基本上是玩抽象类的游戏,允许您灵活地定义它们,无论是通过硬编码还是不通过硬编码

希望能有帮助

司机:

public class Driver {

    public static void main(String[] args) {


        Sports sports = new Basketball("Team1");
        sports = new Baseball();

        sports.printSports();

    }
}

如果您想为switch语句创建一个“正式”模式,我想您可以编写一个访问者。我不是这个模式的超级粉丝,但它似乎适用于你的问题

你可以看看

wiki页面上的示例还解决了与您类似的打印问题

以下是已翻译为您的域语言的模式:

public interface ISport
{
    void Accept(ISportsVisitor visitor);
}

public interface ISportsVisitor 
{
    void Visit(Basketball basketball);
    void Visit(Baseball baseball);
}

public class Baseball : Sport, ISport
{
    // ...
    public void Accept(ISportsVisitor visitor)
    {
        visitor.Visit(this);
    }
    //...
}

public class SportsPrinter : ISportsVisitor
{
    public void Visit(Basketball basketball)
    {
        // Print basketballs
    }

    public void Visit(Baseball baseball)
    {
        // Print baseballs
    }
}
然后在主应用程序中:

var sportsPrinter = new SportsPrinter();

foreach(var sport in sports)
{
    sport.Accept(sportsPrinter);
}
这是一个非常奇怪的模式,它不能很好地表达意图。我想你可以偏离标准术语来尝试改进它。然而,在您有了这个模式之后,您可以向您的域模型添加其他功能,而无需触摸它们

如果需要返回类型,那么可以将访问者界面更改为返回类型。假设你的一些运动项目可以有队长,而其他项目则没有队长(例如网球),你需要一份所有运动项目的队长名单。您可以有这样一个界面:

public interface IAnotherSportsVisitor
{
    Person Accept(Baseball basball);
    // And an accept method for the relevant sports
}

public class CaptainCollectionVisitor : IAnotherSportsVisitor
{
    public Person Visit(Baseball baseball)
    {
        return baseball.GetCaptain();
    }

    public Person Visit(Tennis tennis)
    {
        return null; // or maybe return GetTeamManager()? 
    }
}

public class Baseball : ISport
{
    //...
    public Person Accept(IAnotherSportsVisitor visitor)
    {
        return visitor.Visit(this);
    }
    //...
}

public class Tennis: ISport
{
    //...
    public Person Accept(IAnotherSportsVisitor visitor)
    {
        return visitor.Visit(this);
    }
    //...
}
在您的主要应用程序中:

var captains = sports.Select(x => x.Accept(captainCollectionVisitor)).Where(x => x!= null);

这是一个选项,或者你可以有一个“Balls”(我很想说“IBalls”,但在十多年前就停止使用这个符号)接口,然后检查这个接口。如果存在,您可以调用
getBalls
,它返回
Ball
的集合,并为Ball创建另一个类/类层次结构。要展开上述内容,您可以定义一个通用参数
并创建
getBalls()
return
List
并将其子类化为
Basketball extensed Sports
@DaveNewton感谢dave的回复,我会更深入地研究这种格式,因为它可能适合我的需要。球的继承权可能有用,只是我可能需要做一点额外的工程,这很好。我同意类型铸造。对于Sports子类中的这些重写方法,我将如何处理返回类型。如果返回List vs,我仍然需要某种类型的控制语句来处理要检索的类型?如果你说List(但我认为Sports不能是抽象的)作为方法的返回类型,当你在List中插入一个扩展Sports的类时,你调用“universal”方法,不同的类型将调用不同的方法,返回类型将相同(列表),您可以继续使用它。这是隐藏在类后面的调用。对于运动的子类中的这些重写方法,我将如何处理返回类型。如果只是打印的话,我想那就好了,但是是关于检索的吗?如果返回List vs,我仍然需要某种类型的控制语句来处理要检索的类型?在这种情况下,返回类型将类似于
ListYeah,我看到使用
ListYeah需要检查子类的实际类型(无论是通过检查类型本身还是通过检查静态标志)通常是糟糕的设计。例如,如果您想添加另一个子类,您现在必须在两个地方进行更改——首先,在您正在创建的新类中;第二,在处理不同子类的超类方法中,我同意静态标志的糟糕设计,忽略了这个路由。你和其他人肯定给了我一条更好的途径,这个例子要求打电话的人重新开始所有可能的运动。在这种情况下,您已经有了所有可能的运动的列表。还是不?printSports()可能是静态的,因为它不涉及与特定运动实例相关的任何逻辑。这将揭示一个问题,即printSports()方法依赖于运动构造函数的x调用才能正常运行。我认为他了解所有运动,因为他列出了它们。但是是的,如果你不知道所有的运动,不要使用这个,这是很明显的。是的,可以使用打印运动方法
var sportsPrinter = new SportsPrinter();

foreach(var sport in sports)
{
    sport.Accept(sportsPrinter);
}
public interface IAnotherSportsVisitor
{
    Person Accept(Baseball basball);
    // And an accept method for the relevant sports
}

public class CaptainCollectionVisitor : IAnotherSportsVisitor
{
    public Person Visit(Baseball baseball)
    {
        return baseball.GetCaptain();
    }

    public Person Visit(Tennis tennis)
    {
        return null; // or maybe return GetTeamManager()? 
    }
}

public class Baseball : ISport
{
    //...
    public Person Accept(IAnotherSportsVisitor visitor)
    {
        return visitor.Visit(this);
    }
    //...
}

public class Tennis: ISport
{
    //...
    public Person Accept(IAnotherSportsVisitor visitor)
    {
        return visitor.Visit(this);
    }
    //...
}
var captains = sports.Select(x => x.Accept(captainCollectionVisitor)).Where(x => x!= null);