java中为什么要少用继承多用组合

一、前言

最近的接收的一套代码,真是吐血,我在代码审查的时候发现系统代码一大堆问题,阅读起来非常艰涩难懂,主要是系统代码中使用了大量得到继承,什么都是继承。而且是嵌套多层。这种设计真的很垃圾。继承在代码中本来是好事,但是用的多了就是坏事了,特别是嵌套层次多的继承。

二、java继承

Java中的继承是一种面向对象编程(OOP)的重要特性,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,子类可以重用父类的代码,并且可以添加或覆盖父类的属性和方法,以实现更具体的功能。

继承的基本语法

在Java中,使用extends关键字来实现继承。下面是一个简单的例子:

class Animal {  
    void eat() {  
        System.out.println("The animal eats");  
    }  
}  
  
class Dog extends Animal {  
    void bark() {  
        System.out.println("The dog barks");  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Dog dog = new Dog();  
        dog.eat();  // 继承自Animal的方法  
        dog.bark(); // Dog类自己的方法  
    }  
}

在这个例子中,Dog类继承了Animal类。因此,Dog类的对象可以调用eat()方法,这个方法是从Animal类继承来的。同时,Dog类还定义了自己的bark()方法。

继承的特点

  1. 代码重用:子类可以继承父类的属性和方法,避免了在子类中重复编写相同的代码。

  2. 扩展性:子类可以在继承父类的基础上添加新的属性和方法,或者覆盖父类的方法以实现不同的行为。

  3. 多态性:通过继承,子类对象可以被视为父类对象处理,这是多态性的基础。

继承的层次结构

Java中的继承是单一继承的,即一个类只能直接继承自一个父类。但是,一个类可以间接地继承自多个类,通过继承链实现。例如,如果类B继承自类A,类C又继承自类B,那么类C间接地继承自类A。

访问修饰符与继承

访问修饰符(如publicprotecteddefault(无修饰符)和private)决定了类的成员(属性和方法)的可访问性。在继承中,不同访问修饰符的成员具有不同的可继承性:

  • public:子类可以访问父类的public成员。
  • protected:子类、同一个包中的其他类以及任何其他类的子类都可以访问protected成员。
  • default(无修饰符):子类以及同一个包中的其他类可以访问无修饰符的成员。
  • privateprivate成员只能被其所在的类访问,不能被子类访问。

重写(Overriding)

子类可以提供一个与父类方法签名相同但实现不同的方法,这称为方法重写。当通过子类对象调用这个方法时,会执行子类中的方法实现,而不是父类中的。重写方法时,访问修饰符的可见性不能低于父类中被重写方法的可见性。

构造方法与继承

子类不能继承父类的构造方法,但子类构造方法可以通过super关键字调用父类的构造方法。如果子类构造方法没有显式地调用父类的构造方法,那么它会自动调用父类的无参数构造方法。如果父类没有定义无参数的构造方法,且子类构造方法中没有通过super显式调用父类的其他构造方法,则编译器会报错。

通过继承,Java代码可以更加模块化、可维护,并且提高了代码的重用性。然而,过度使用继承也可能导致代码结构变得复杂和难以管理,因此在实际编程中需要谨慎使用。

三、看看垃圾代码

    /**
     * 获取商品可用店铺列表
     */
    @ActionConstructInit(parameterVoName = "requestProductDetailModel")
    public List<SysStore> getStoreList() {
        RequestProductDetailModel requestProductDetailModel = getRequestProductDetailModel();
        Long skuId = requestProductDetailModel.getSkuId();
        ProSku sku = new ProSku();
        sku.setId(skuId);
        sku.load();
        if (sku.getIsLoad()) {
            if (StringUtils.isNotBlank(sku.getApplyStoreCodes())) {
                List<String> storeCodeList = Arrays.asList(sku.getApplyStoreCodes().split(","));
                SysStore sysStore = new SysStore();
                sysStore.addConditions("inStoreCode", storeCodeList);
                return sysStore.select();
            } else {
                return StoreUtil.queryOfflineStoreByMchOuCode(sku.getMchOuCode());
            }
        }
        return new ArrayList<>();
    }

 

子子孙孙无穷无尽也。

一个业务类里写上了 8000千 一万的的代码,也是服了

 

四、java组合

在Java中,"组合"(Composition)是一种实现代码复用和构建复杂对象结构的重要技术。它允许一个类的对象包含另一个类的对象作为自己的属性,这样新对象就可以继承被包含对象的行为和状态。与继承相比,组合是一种更加灵活且松耦合的方式来扩展对象的功能。

组合的一个关键优势在于它允许你构建更加灵活和可维护的代码。通过使用组合,你可以将对象组合成更复杂的对象,而这些对象可以独立地变化,而不会影响其他对象。

下面是一个简单的Java组合示例:

 

// 被组合的对象  
class Engine {  
    void start() {  
        System.out.println("Engine started");  
    }  
}  
  
// 组合了Engine对象的对象  
class Car {  
    private Engine engine; // 组合了Engine对象  
  
    public Car() {  
        this.engine = new Engine(); // 初始化Engine对象  
    }  
  
    void startCar() {  
        engine.start(); // 调用Engine对象的start方法  
        System.out.println("Car started");  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Car car = new Car();  
        car.startCar(); // 输出:Engine started 和 Car started  
    }  
}

在这个例子中,Car类组合了一个Engine对象。当调用Car对象的startCar方法时,它会首先调用Engine对象的start方法,然后再执行自己的逻辑。

组合与继承的主要区别在于:

  • 继承:子类继承父类的属性和方法,子类可以重写父类的方法或添加新的方法。继承是"is-a"关系,例如,DogAnimal的一种。
  • 组合:一个类的对象包含另一个类的对象作为自己的属性。组合是"has-a"关系,例如,Car有一个Engine

组合通常比继承更加灵活,因为它允许你动态地改变被组合对象的类型,而继承则是一种静态的关系,一旦确定子类与父类的关系,就不能轻易改变。此外,过度使用继承可能导致类层次结构变得复杂和难以维护,而组合则可以通过将对象组合成更小的、更易于管理的部分来避免这个问题。

五、java为什么要多用组合少用继承

在Java中,推荐多用组合少用继承的原因主要有以下几点:

  1. 避免多继承的局限性:Java不支持多继承,这意味着一个类只能继承自一个父类。因此,如果希望赋予一个类多个功能,组合(通过接口和成员变量)是一个更灵活的选择。
  2. 提高测试的可维护性:在单元测试中,使用组合可以使mock数据更加容易。当使用继承时,可能需要mock整个基类,而使用组合则可以通过注入不同的实例来方便地完成mock和线上实例的切换。
  3. 满足设计模式的需要:现有成熟的设计模式,如策略模式(Strategy design pattern)和装饰者模式(Decorator design pattern),都倾向于使用组合的形式。这些模式通过组合不同的对象和行为来实现灵活性和可扩展性。
  4. 减少封装问题:继承中,子类对父类的依赖可能导致子类变得脆弱。一旦父类行为发生变化(如代码结构或性能优化等原因),子类也可能受到影响。而组合通过显式地包含所需的对象和功能,减少了这种依赖性问题。
  5. 实现更灵活的代码复用:通过聚合/组合关系,可以避免继承带来的方法污染问题,具有很强的代码重用性和灵活性。聚合/组合复用也可以在运行时动态进行,这使得组合能够更灵活地适应不同的需求和场景。
  6. 解决复杂的继承关系:当继承层次过深或过复杂时,会影响代码的可维护性。在这种情况下,使用组合可以更有效地管理类的结构和关系,减少继承带来的复杂性。

总的来说,虽然继承是面向对象编程的一个重要特性,但在Java中,由于多继承的限制和上述优势,推荐使用组合来扩展类的功能。当然,在实际的项目开发中,我们还需要根据具体的情况和需求来选择使用继承还是组合。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋力向前123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值