Использование абстрактных классов и доступ к ним как к одной сущности, ООП Дизайн? - PullRequest
0 голосов
/ 01 июня 2018

Я не уверен в точном способе реализации моих классов.

Скажем, у меня есть классы по бейсболу и баскетболу, которые имеют характеристики, отличающиеся друг от друга, и оба расширяют виды спорта.

Мой пример,у меня есть:

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.
}

Скажи, что я хочу List<Sports> sports, который содержит все определенные виды спорта.Но когда я получаю доступ к этим спискам, я хочу напечатать списки баскетбольных и баскетбольных мячей в зависимости от того, что это такое.Нужно ли будет набирать приведение, чтобы выяснить, какой метод вызывать?Это плохой дизайн?

Еще одна мысль, которая у меня была, но это, кажется, небольшая ручная работа, а не правильная. Lol.

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;
    }
}

Так что, когда я перебираю этот объект где-то, я могусделайте

switch (type) {
case "Baseball":
    // Iterate and print baseball list.
case "Basketball":
    // Iterate and print basketball list.
}

и в этом случае скажем, что Бейсбол и Баскетбол так сильно отличаются друг от друга, у них 0 сходных характеристик.

Но тогда у меня будет неиспользованное объявление для Бейсбола и то же самое дляБаскетбол.

Ответы [ 4 ]

0 голосов
/ 08 июня 2018

Если вам нужен «формальный» шаблон для этого оператора switch, я полагаю, вы могли бы написать посетителя.Я не большой поклонник этой модели, но она кажется применимой к вашей проблеме.

Вы можете взглянуть на https://en.wikipedia.org/wiki/Visitor_pattern

Пример на странице вики также решает проблему печати, аналогичную вашей.

Вот шаблон, переведенный в ваш доменlanguage:

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);
0 голосов
/ 01 июня 2018

Если я понимаю, вам нужен один и тот же метод для разных типов списков.Кастинг не всегда хорошая идея, вам нужен интерфейс.Это как универсальный «класс» с вашими методами.Код для интерфейсов практически одинаков, и вы можете реализовать в своих классах то, что вы хотите, и интерфейс будет выбирать, какой метод вызывать, зависит от типа. Методы в интерфейсе и в классах должны быть одинаковыми, а классы должны реализовывать интерфейс.

0 голосов
/ 01 июня 2018

Ваш второй код намного лучше, хотя все еще не хватает чего-то, вот код, о котором я говорю:

    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;
        }
    }

Теперь обратите внимание, что спорт не делает ничего, кроме того, что содержит 2 спискакоторые содержат классы «баскетбол» и «бейсбол», представляющие команды.

Лучше было бы сказать, что баскетбол и бейсбол - это оба вида спорта, и я пытаюсь представлять спортивные команды (я нена самом деле не знаю, насколько всеобъемлющим вы хотите заниматься спортом, например: классифицируются ли виды спорта по определенному признаку? Например: эти виды спорта включают использование мяча или команду из 5 человек и т. д ... [Извините, я не большой в спорте]), эти спортивные команды имеют такие атрибуты:

public abstract class Sports {

    private static List<Sports> teams = new ArrayList<>();
    private int size;
    private String teamName;



    public Sports(String teamName) {

        this.teamName = teamName;
        teams.add(this);

    }

    public Sports(String teamName, int size) {
        this.size = 0;
        this.teamName = teamName;
        teams.add(this);
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getSize() {
        return size;
    }

    public String getTeamName() {
        return teamName;
    }

    public void printSports() {

        Iterator<Sports> it = teams.iterator();

        while(it.hasNext()) {

            Sports tmp = it.next();

            if(tmp instanceof Basketball) {
                System.out.println(tmp.getTeamName());
            }else if(tmp instanceof Baseball) {
                System.out.println("Something else");
            }
        }
    }

    public abstract int getTeamSize();
    public abstract void setTeamSize(int sizeOfTeam);

}

Баскетбольный класс:

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;
    }
}

Я упростил это, хотя этогораздо лучше, вы можете определить любой атрибут, как вы хотите, и автоматически добавить его в список, который всегда будет там до конца программы.Вы можете сделать объект в другом классе (см. Ниже, я использовал драйвер), или просто добавить материал в список непосредственно в самом классе «Спорт», например, создать столько спортивных объектов, сколько вы хотите, и вы сами их содержали.Что касается бейсбола и баскетбола, я дал вам два примера классов, которые были упрощены, но в основном играют в игру абстрактного класса, что позволяет вам быть гибкими в том, как вы их определяете, жестким кодированием или нет.

Надеюсь, это поможет.

Драйвер:

public class Driver {

    public static void main(String[] args) {


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

        sports.printSports();

    }
}
0 голосов
/ 01 июня 2018

Звучит так, как будто у вас есть операция, которую вы хотите выполнять с любым Sports объектом, независимо от его фактического типа.Для этого вы хотите определить его в базовом классе (вероятно, abstract), а затем включить соответствующие реализации в дочерние классы.

Например, вы должны дать Sports метод: protected abstract void printBalls()

И затем реализовать его соответствующим образом в каждом подклассе.Например, в Baseball вы могли бы иметь:

@Override
protected abstract void printBalls() {
  for(Baseball baseball: this.getBaseballs()) {
    System.out.println(baseball);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...