java - 组合与继承(如何理解 Java 中的 Thinking)

标签 java inheritance

你能帮我理解下面写的内容吗?这是来自 Thinking in Java 一书。

Because you are composing a new class from existing classes, this concept is called composition(if the composition happens dynamically, it's usually called aggregation).

Composition is often referred to as a "has-a" relationship, as in "A car has an engine."

Composition comes with a great deal of flexibility. The member objects of your new class are typically private, making them inaccessible to the client programmers who are using the class. This allows you to change those members without disturbing existing client code. You can also change the member objects at runtime, to dynamically change the behavior of your program. Inheritance, which is described next, does not have this flexibility since the compiler must place compile-time restrictions on classes created with inheritance.

Because inheritance is so important in object-oriented programming, it is often highly emphasized, and the new programmer can get the idea that inheritance should be used everywhere. This can result in awkward and overly complicated designs. Instead, you should first look to composition when creating new classes, since it is simpler and more flexible.

没有例子我就无法捕获这个果冻。您能给我提供以下示例吗:

  1. 聚合,即动态发生的组合。

  2. 继承面临编译时限制。

我的意思是,我正在寻找揭示组合相对于继承的优势的示例。

稍后添加:我需要代码示例(而不是描述)。

最佳答案

I mean that I'm looking for examples revealing advantages of composition over inheritance.

假设您有一个顶级抽象AbstractCar。如果你要创建一个强大的继承关系,你会有类似的东西

abstract class AbstractCar {
    protected abstract void startEngine();
}

class FastCar extends AbstractCar {
    @Override
    public void startEngine() {
        System.out.println("turn key... vroom");
    }
}

就功能而言,这看起来很符合要求,因为汽车应该具有启动发动机的功能。但是,如果您想关闭发动机或为发动机安装插入启动功能,该怎么办?您必须更改实现。

更好的方法是将引擎功能提取到 Engine 类中,并将其封装到 AbstractCar 中。 Engine 将是一个顶级抽象,其实现可以更改,并且您可以使用 Engine 作为类型,同时允许引擎实现更改。例如

interface Engine {
    void startEngine();
} 

class PushStartEngine implements Engine {
    @Override
    public void startEngine() {
        System.out.println("push button.. vrooom");
    }
}

abstract class AbstractCar {
    protected Engine engine;
    protected void setEngine(Engine engine) {
        this.engine = engine;
    }
    protected void getEngine() {
        return engine;
    }
}

class FastCar extends AbstractCar {
    public FastCar() {
        setEngine(new KeyStartEngine());
    }
}

这可能不是最好的示例(因为它仍然强加了紧密的类型耦合 - 还有其他设计模式可以解决这个问题),但它应该为您提供组合相对于继承的优势的示例。提取变化的基本前提是,在本例中是引擎。在字符串继承关系中,您可能会在顶级抽象中定义更多功能,但是当您喜欢组合继承时,您可以将该功能封装到其他对象中。这允许更轻松的扩展和更改。

因此,通过上面的示例,您现在可以轻松切换引擎,这在继承的情况下是不可能的

public static void main(String[] args) {
    // let's say you have another OlderCar implmentation
    // that has a KeyStartEngine
    OlderCar car = new OlderCar();
    car.getEngine().startEngine();

    // I just hit the lotto, lets upgrade!
    PushStartEngine engine = store.buyPushStartEngine();
    car.setEngine(engine);
    car.getEngine().startEngine();
}

关于java - 组合与继承(如何理解 Java 中的 Thinking),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24464947/

相关文章:

java - 如果我想使用我知道它在大多数用户计算机中不可用的特定字体

C++ 将派生类存储在单个 vector 中,派生类不包含重新定义的方法

java - Hive UDF 未返回预期结果

java - 文件输入流错误Java : error reading file

java - 单元测试 OSGI 包

c++ - 使用 ArrayList 实现选择排序

c++ - C++ 中继承的运行时成本(没有虚拟性)?

delphi - Delphi中的继承: Does each of Delphi Subclasses have its own unique copy of the Superclass Private Fields?

Java - 继承的方法com.example.project.ConcreteA无法隐藏com.example.project.MyInterface中的抽象方法

java - 随机游览生成问题