📚 Mastering Object-Oriented Composition | 掌握面向对象组合
In object-oriented programming, understanding how to build complex systems from simpler parts is essential. Composition is a fundamental design technique where a class contains objects of other classes to reuse and delegate functionality. This article explores composition in depth for Edexcel A-Level programming, contrasting it with inheritance and demonstrating best practices using Python.
在面向对象编程中,理解如何通过简单部件构建复杂系统至关重要。组合是一种基本设计技术,即一个类包含其他类的对象以实现功能复用与委托。本文深入探讨组合概念,并将其与继承进行对比,使用 Python 演示最佳实践,紧扣 Edexcel A-Level 编程大纲。
1. What Is Object-Oriented Composition? | 什么是面向对象组合?
Composition is a “has-a” relationship where a class is made up of one or more objects from other classes. Instead of inheriting behaviour, an object delegates tasks to its components. For example, a Car has an Engine, and instead of extending an Engine class, the Car class contains an Engine instance.
组合是一种“拥有”关系,即一个类由一个或多个其他类的对象构成。与继承行为不同,对象将任务委托给它的组件。例如,一辆汽车拥有引擎,汽车类并不继承引擎类,而是包含一个引擎实例。
2. Inheritance vs. Composition: Choosing the Right Relationship | 继承与组合:选择合适的关系
Inheritance models an “is-a” relationship, ideal when a subclass truly specializes a superclass. Composition models a “has-a” relationship and offers greater flexibility because you can change components at runtime. The Gang of Four principle advises “favour composition over inheritance” to avoid deep, rigid class hierarchies.
继承建模“是一个”关系,适用于子类真正特化父类的情形。组合建模“拥有”关系,并提供更大的灵活性,因为你可以在运行时更换组件。GoF设计原则建议“优先使用组合而非继承”,以避免深层僵化的类层次结构。
- Inheritance: Tight coupling; fragile base class problem.
- 继承:紧耦合;脆弱基类问题。
- Composition: Loose coupling; easier to modify and test.
- 组合:松耦合;更易于修改和测试。
3. Basic Implementation of Composition in Python | Python 中组合的基本实现
To implement composition, define a class that stores a reference to another object as an instance attribute. The outer class then uses this attribute to access the inner object’s methods. No special syntax is required beyond standard object orientation.
要实现组合,定义一个类,将另一个对象的引用存储为实例属性。外部类随后使用该属性访问内部对象的方法。除了标准的面向对象语法外,不需要其他特殊语法。
class Engine:
def start(self):
return "Engine started"
class Car:
def __init__(self):
self.engine = Engine() # composition
def drive(self):
return self.engine.start() + " – car is moving"
Here, Car relies on an Engine object, but the Engine class can be developed independently and even replaced with a mock for testing.
此处,Car 依赖于一个 Engine 对象,但 Engine 类可以独立开发,甚至可以替换为模拟对象进行测试。
4. Delegation: The Heart of Composition | 委托:组合的核心
Delegation means an object passes the execution of a task to another object. In composition, the containing object forwards requests to its components. This keeps responsibilities clearly separated and follows the Single Responsibility Principle.
委托是指一个对象将任务执行传递给另一个对象。在组合中,容器对象将请求转发给其组件。这样职责清晰分离,遵循单一职责原则。
For example, a Order class may delegate payment processing to a PaymentGateway object, keeping order logic clean.
例如,Order 类可将支付处理委托给 PaymentGateway 对象,使订单逻辑保持整洁。
5. Aggregation: A Weaker Form of Composition | 聚合:组合的一种弱形式
Aggregation is a specialised type of composition where the contained objects can exist independently of the container. In UML, aggregation is shown with an empty diamond. For instance, a University has Student objects, but a student survives even if the university is closed.
聚合是一种特殊的组合形式,其中被包含的对象可以独立于容器存在。在 UML 中,聚合用空心菱形表示。例如,University 拥有 Student 对象,但即使大学关闭,学生依然存在。
Aggregation and composition (strong ownership/“death” of parts with whole) are both “has-a” relationships, but composition implies the parts cannot exist without the whole.
聚合和组合(强拥有权,部分随整体消亡)都是“拥有”关系,但组合隐含部分不能独立于整体存在。
6. Designing a Flexible System with Dependency Injection | 使用依赖注入设计灵活系统
Hard-coding object creation inside a class reduces flexibility. Dependency injection passes the component into the class via the constructor, making the code more testable and reusable. Combat tight coupling by accepting interfaces or abstract base classes.
在类内部硬编码对象创建会降低灵活性。依赖注入通过构造函数将组件传入类中,使代码更具可测试性和可重用性。通过接受接口或抽象基类来对抗紧耦合。
class Engine:
def start(self):
return "Vroom"
class ElectricEngine:
def start(self):
return "Hum"
class Car:
def __init__(self, engine):
self.engine = engine # injected dependency
Now a Car can work with any engine that has a start() method, demonstrating polymorphism through composition.
现在 Car 可以与任何具有 start() 方法的引擎一起使用,展示了通过组合实现的多态。
7. Composition in the Larger OOP Ecosystem: Patterns | 面向对象生态系统中的组合:设计模式
Many design patterns rely on composition. The Strategy pattern encapsulates interchangeable algorithms; the Decorator pattern dynamically adds responsibilities through wrapping. Edexcel A-Level students should recognise that composition enables these patterns without heavy inheritance.
许多设计模式依赖组合。策略模式封装可互换的算法;装饰器模式通过包装动态添加职责。Edexcel A-Level 学生应认识到组合能够支持这些模式,而无需大量继承。
- Strategy pattern: A
Duckhas aFlyBehaviourobject. - 策略模式:
Duck拥有一个FlyBehaviour对象。 - Decorator pattern: A
Mochawraps aBeverageobject. - 装饰器模式:
Mocha包装一个Beverage对象。
8. Composition and the SOLID Principles | 组合与 SOLID 原则
SOLID principles encourage maintainable design. Composition directly supports:
SOLID 原则提倡可维护设计。组合直接支持:
- Single Responsibility: each component does one job.
- S单一职责:每个组件只做一件事。
- Open/Closed: classes open for extension by swapping components, not modifying the class.
- O开闭原则:通过替换组件而不是修改类来扩展。
- Dependency Inversion: depend on abstractions, not concretions, injected through composition.
- D依赖倒置:依赖抽象而非具体实现,通过组合注入。
Using composition wisely naturally aligns with writing SOLID code.
明智地使用组合自然会写出符合 SOLID 原则的代码。
9. Testing Code with Composition and Mock Objects | 使用组合与模拟对象测试代码
Because composed objects are referenced through attributes, testing becomes straightforward. You can replace real components with mock objects that simulate expected behaviours, isolating the unit under test. This is a huge advantage over inheritance where behaviours are often mixed.
由于组合对象通过属性引用,测试变得简单明了。你可以用模拟对象替换真实组件,模拟预期行为,隔离测试单元。这比行为常常混合的继承具有巨大优势。
from unittest.mock import Mock
def test_car():
mock_engine = Mock()
mock_engine.start.return_value = "mock"
car = Car(mock_engine)
assert "mock" in car.drive()
Here, the Car class is tested without a real engine, improving test reliability and speed.
这里,Car 类在没有真实引擎的情况下被测试,提高了测试可靠性和速度。
10. Performance and Memory Considerations | 性能与内存考量
Composition involves object instantiation and method delegation overhead, but in most applications this is negligible. It can actually improve memory efficiency by sharing components via references. In A-Level exam contexts, understand that extra indirection may slightly impact speed compared to direct code, but maintainability gains are significant.
组合涉及对象实例化和方法委托开销,但在大多数应用中可忽略不计。它实际上可以通过引用共享组件来提高内存效率。在 A-Level 考试中,要理解与直接代码相比额外间接层可能轻微影响速度,但可维护性的提升是显著的。
Use composition when code clarity and flexibility matter more than micro-optimisations.
当代码清晰度和灵活性比微优化更重要时,使用组合。
11. Common Mistakes Students Make | 学生常犯的错误
A typical error is confusing composition with aggregation. Ensure you can explain: composition implies life-cycle dependency (Engine is destroyed with Car). Another mistake is creating overly complex compositions when inheritance would be simpler; evaluate the relationship type.
一个典型错误是混淆组合与聚合。确保你能解释:组合意味着生命周期依赖(引擎随汽车销毁)。另一个错误是在继承更简单时创建过于复杂的组合;应评估关系类型。
Also, many students forget to use dependency injection, leading to tightly coupled spaghetti code. Always ask: “Can I swap this part easily?”
此外,许多学生忘记使用依赖注入,导致紧耦合的意大利面条式代码。始终问自己:“我能轻松替换这个部分吗?”
12. Summary and Exam Tips for Edexcel A-Level | 总结与 Edexcel A-Level 考试技巧
Composition is a “has-a” relationship that promotes reusability, maintainability, and testability. In Edexcel A-Level papers, you may be asked to compare inheritance and composition, identify relationships in UML diagrams, or write code illustrating composition with Python. Practice writing clean, composed classes with dependency injection.
组合是一种“拥有”关系,能促进可重用性、可维护性和可测试性。在 Edexcel A-Level 试卷中,你可能需要比较继承与组合,识别 UML 图中的关系,或编写 Python 代码演示组合。练习编写具有依赖注入的整洁组合类。
Remember: “Favour composition over inheritance” does not mean never use inheritance; it means use it when subclassing truly models a specialisation. For everything else, delegate.
请记住:“优先使用组合而不是继承”并不意味着永远不使用继承;而是当子类真正建模一种特化时才使用继承。对于其他情况,委托吧。
Published by TutorHao | Programming Revision Series | aleveler.com
更多咨询请联系16621398022(同微信)
屏轩国际教育cambridge primary/secondary checkpoint, cat4, ukiset,ukcat,igcse,alevel,PAT,STEP,MAT, ibdp,ap,ssat,sat,sat2课程辅导,国外大学本科硕士研究生博士课程论文辅导