You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

抽象类统一管理不同球类对象的OOP设计实现疑问

问题描述

我现在不确定类的具体实现方式。现有Baseball和Basketball两类,二者特性完全不同,均继承抽象类Sports,初始代码如下:

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

public class Baseball extends Sports { 
    public List<Baseballs> getBaseballs() { 
        // 获取另一个对象baseballs的列表
    } 
    // 实现抽象方法
} 

public class Basketball extends Sports { 
    public List<Basketballs> getBasketballs() { 
        // 获取另一个对象basketballs的列表
    } 
    // 实现抽象方法
} 

我希望创建List<Sports> sports集合管理所有球类对象,但遍历该集合时需根据对象类型打印对应的专属列表(如Baseballs或Basketballs列表)。请问是否需要通过类型转换来调用对应方法?这种设计是否不合理?

我还想到另一种实现方案,但需手动处理且存在问题,代码如下:

public class Sports { 
    String sportType = "[Sport]"; 
    List<Basketball> basketballs; 
    List<Baseball> baseballs; 
    public void 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判断sportType来处理:

switch (type) { 
    case "Baseball": 
        // 遍历并打印baseball列表
        break;
    case "Basketball": 
        // 遍历并打印basketball列表
        break;
} 

但此方案会存在未使用的属性(如Baseball对象中的basketballs属性),请问合理的OOP实现方式是什么?


合理的OOP实现方案

其实你完全不用纠结类型转换或者冗余属性的问题,利用OOP的多态特性就能优雅解决这个需求,完美契合开闭原则和单一职责原则。

核心思路:让子类自己管自己的专属逻辑

简单来说,就是把“打印专属列表”这个行为,交给各个球类子类自己去实现,抽象类只定义统一的行为规范。这样遍历List<Sports>的时候,直接调用统一方法就行,根本不用判断对象类型。

第一步:给抽象类加统一的行为规范

修改Sports抽象类,新增一个抽象方法printExclusiveList(),用来定义“打印专属列表”这个统一行为:

public abstract class Sports { 
    public abstract String getSport(); 
    public abstract String getCoach(); 
    public abstract void getTeamSize(); 
    // 新增:统一的打印专属列表方法
    public abstract void printExclusiveList();
} 

第二步:子类实现自己的专属打印逻辑

在Baseball和Basketball里,分别实现printExclusiveList()方法,各自处理自己的专属列表打印,同时每个子类只持有自己需要的列表属性,完全没有冗余:

public class Baseball extends Sports { 
    private List<Baseballs> baseballs; 

    // 用构造方法初始化列表
    public Baseball(List<Baseballs> baseballs) {
        this.baseballs = baseballs;
    }

    @Override
    public String getSport() {
        return "Baseball";
    }

    @Override
    public String getCoach() {
        return "棒球教练";
    }

    @Override
    public void getTeamSize() {
        System.out.println("The size of the baseball team is 9.");
    }

    @Override
    public void printExclusiveList() {
        System.out.println("棒球专属列表:");
        for (Baseballs item : baseballs) {
            // 这里打印Baseballs对象的具体信息,比如item.getName()之类的
            System.out.println(item.toString());
        }
    }

    // 如果外部需要获取列表,也可以保留这个方法,但打印逻辑已经封装在子类里了
    public List<Baseballs> getBaseballs() {
        return baseballs;
    }
} 
public class Basketball extends Sports { 
    private List<Basketballs> basketballs; 

    public Basketball(List<Basketballs> basketballs) {
        this.basketballs = basketballs;
    }

    @Override
    public String getSport() {
        return "Basketball";
    }

    @Override
    public String getCoach() {
        return "篮球教练";
    }

    @Override
    public void getTeamSize() {
        System.out.println("The size of the basketball team is 5.");
    }

    @Override
    public void printExclusiveList() {
        System.out.println("篮球专属列表:");
        for (Basketballs item : basketballs) {
            System.out.println(item.toString());
        }
    }

    public List<Basketballs> getBasketballs() {
        return basketballs;
    }
} 

第三步:遍历集合时直接调用统一方法

现在管理List<Sports>的时候,遍历代码超级简洁,多态会自动帮你调用对应子类的实现,完全不用类型转换或者switch判断:

List<Sports> sports = new ArrayList<>();
// 假设已经初始化了baseballList和basketballList
sports.add(new Baseball(baseballList));
sports.add(new Basketball(basketballList));

for (Sports sport : sports) {
    sport.printExclusiveList();
    sport.getTeamSize(); // 其他抽象方法也能正常调用
}

为什么这个方案更优?

  • 彻底避免类型转换:不用在遍历的时候判断对象类型,代码更简洁,也不会出现类型转换错误的风险。
  • 符合开闭原则:以后如果新增其他球类(比如Football),只需要新增一个Football子类实现Sports的抽象方法就行,完全不用修改现有的遍历逻辑。
  • 消除冗余属性:每个子类只持有自己需要的列表属性,不会像你之前的方案那样出现“Baseball对象带着basketballs属性”这种不合理的情况,完美符合单一职责原则。

解答你之前的几个疑问

  1. 是否需要类型转换?:用上面的多态方案完全不需要,类型转换属于“向下转型”,是一种比较脆弱的写法,容易出错,应该尽量避免。
  2. 第一种设计是否不合理?:你最初的抽象类设计没问题,只是缺少了统一的行为方法来封装子类的专属逻辑,补充之后就非常合理了。
  3. 第二种方案的问题:它违背了单一职责原则,一个类持有了不属于自己的属性,而且switch判断的写法会让代码变得臃肿,新增球类时还要修改switch分支,完全不符合开闭原则。

内容的提问来源于stack exchange,提问作者Ziic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:00:12