游戏开发--依赖倒置原则
游戏开发--依赖倒置原则(DIP)
此原则涵盖两大核心理念:
1、高层模块不应直接依赖于低层模块,而应共同依赖于抽象层面;
2、抽象接口的设计不应受制于具体实现,而应让具体实现遵循抽象接口的标准。
为了更直观地理解第一个核心理念(高层模块不应依赖于低层模块),我们以日常生活中的汽车为例进行说明,或许比单纯从软件设计的角度阐述更为通俗易懂。
汽车与汽车引擎便是一个典型的高层与低层依赖关系实例。汽车作为高层模块,在组装过程中需要诸多低层模块(如引擎、传动系统、轮胎、车身结构等)的协同配合。然而,汽车往往受限于引擎类型。汽油车无法兼容柴油,柴油车也无法改用汽油。每次加油时,都必须根据引擎类型选择相应的加油设施,汽车的加油选项因此受到引擎的制约。尽管这种现状难以改变,但在软件系统设计中,却有多种手段可以避免“高层依赖低层”的问题,即通过反转两者之间的依赖关系,让低层模块依据高层模块定义的接口来实现功能。
再以电脑为例,电脑作为高层模块定义了USB接口,该接口明确了硬件规格及软件驱动程序的编写要求。任何符合USB接口标准的低层模块(如存储卡、手机、U盘、读卡器等)均可接入电脑,成为其组成部分。这一过程展示了如何从“高层模块定义接口”到“底层模块遵循接口实现”的依赖反转。同时,也体现了第二个核心理念:“抽象接口不应依赖于具体实现,而应让具体实现遵循抽象接口”。高层模块与低层模块的通信应仅通过接口进行,接口的具体实现可能以类变量或对象引用的形式存在。在使用这些变量或引用时,应避免类型转换,以免高层模块被限定于某一低层模块的具体实现。此外,子类在实现接口时,应严格遵循接口定义的方法,不应新增额外方法,以确保高层模块无法通过类型转换调用其他方法。
依赖倒置原则的本质在于通过抽象类(接口或抽象类)实现类与模块间的相互独立与互不影响,从而达到松散耦合的目的。在开发中如何遵循这一原则呢?以下是一些建议:
- 尽量让类继承自接口或抽象类,甚至同时继承两者。这是依赖倒置原则的基本要求,因为接口和抽象类提供了抽象层面,使得依赖反转成为可能。
- 变量的声明类型应尽量为接口或抽象类。虽然并非所有情况都绝对如此(如工具类通常无需接口或抽象类),但应尽量遵循这一原则。
- 类应尽量避免从具体类派生。在项目开发初期,确实应避免从具体类派生出子类。然而,这并不是绝对的,因为设计缺陷在所难免。只要继承深度不超过两层,通常是可以接受的。特别是进行项目维护时,为了快速修复bug或进行拓展开发,有时需要通过继承关系覆盖某个方法,而不必拘泥于从最高基类继承。
- 尽量不要覆盖基类的方法。如果基类是一个抽象类且已实现了某个方法,子类应尽量避免覆盖该方法。因为类间依赖的是抽象层面,覆盖抽象方法可能会对依赖的稳定性产生不利影响。