移动开发面向对象设计原则

面向对象设计原则是指导开发者设计灵活、可维护、可扩展代码的核心思想。
这些原则的核心目标是 “高内聚、低耦合”:
单一职责、迪米特法则侧重 “高内聚”(模块 / 对象职责清晰、减少交互);
开闭、里氏替换、接口隔离、依赖倒置、合成复用原则侧重 “低耦合”(模块 / 对象间关联松散、易于扩展)。

一、单一职责原则(Single Responsibility Principle, SRP)

单一职责原则(Single Responsibility Principle,简称 SRP)是面向对象设计中最基础、最核心的原则之一,其核心思想是 “一个类或模块应该只有一个引起它变化的原因”,即只负责一项明确的职责。目的就是让相同职责的代码『高内聚』。

核心定义
职责:指一个类所承担的功能或负责的业务逻辑,通常对应 “引起它变化的原因”。
单一:一个类只能有一个职责,当需求变化时,只会有一个原因导致这个类需要修改。

为什么需要遵守 SRP?
如果一个类承担多个职责,会导致以下问题:

耦合度高:多个职责交织在一起,修改一个职责可能影响其他职责,引发连锁反应(“牵一发而动全身”)。
可读性差:一个类功能混杂,代码逻辑复杂,开发者难以快速理解其核心作用。
可维护性低:职责越多,修改时需要考虑的因素越多,出错风险越高。
复用性差:当需要复用其中一个职责时,不得不引入其他无关的功能代码。

反例(违反 SRP)
一个 UserService 类同时负责 “用户信息管理” 和 “用户登录验证” 两个职责

public class UserService {
   
   
    // 职责1:用户信息管理(增删改查)
    public void addUser(User user) {
   
    ... }
    public void deleteUser(String userId) {
   
    ... }
    
    // 职责2:用户登录验证
    public boolean login(String username, String password) {
   
    ... }
    public void logout() {
   
    ... }
}

正例(遵守 SRP)
将职责拆分到两个类:

// 职责1:用户信息管理
public class UserManager {
   
   
    public void addUser(User user) {
   
    ... }
    public void deleteUser(String userId) {
   
    ... }
}

// 职责2:用户登录验证
public class UserAuthenticator {
   
   
    public boolean login(String username, String password) {
   
    ... }
    public void logout() {
   
    ... }
}

如何判断一个类是否符合 SRP?
问自己:“这个类有几个不同的功能?” 如果能列举出两个及以上独立的功能,可能需要拆分。
观察变化:如果有两个不同的需求变化会导致这个类修改,说明它承担了多个职责。

总结
单一职责原则的本质是 “分离关注点”—— 让每个类 / 模块专注于自己的核心功能,从而降低复杂度、提高代码的可读性、可维护性和复用性。它是面向对象设计的 “基石”,也是写出清晰、稳健代码的第一步。

二、组合/聚合复用原则(Composite Reuse Principle, CRP)

核心思想
优先通过 “组合 / 聚合” 实现代码复用,而非 “继承”,让复用更灵活、可扩展。
用“对象持有(has-a)”替代“类继承(is-a)”

核心优势
其核心解耦价值,在于用“动态持有关系”替代“静态继承绑定”,彻底打破类之间的强耦合链条,其解耦逻辑的关键是“依赖抽象而非具体”,通过让类持有其他类的接口实例(而非具体实现类)
避免了“继承爆炸”带来的耦合膨胀,复杂功能通过组合多个单一职责的组件实现(如滑动+缩放+旋转功能,由三个独立组件组合而成),每个组件仅专注于自身功能,彼此间无依赖,这种“分而治之”的方式,让类与类之间的关联从“层级嵌套的强绑定”转变为“按需组合的弱关联”,任一组件的修改都局限在自身,不会引发连锁反应

请添加图片描述
汽车需要的能源类型和不同颜色,通过组合接口的方式进行依赖。通过定义不同的接口分离功能,再通过实现类实现特定功能,符合单一职责原则。

低耦合: Car 与 Electric 是 “使用” 关系(has-a),Electric 修改不直接影响 Car。依赖接口而非具体实现(如A依赖B的接口IB,B的实现修改不影响A)。

高灵活性: 可动态替换发动机(如通过构造or Set函数传入 Electric),无需修改 Car 类。

避免“继承爆炸”:复杂功能通过组合多个单一职责的类实现,而非多层继承(如TextView若通过继承实现“可点击+可滑动”会导致层级臃肿,组合ClickHandler+ScrollHandler更清晰)。

缺点:
接口定义成本:需为每个可组合的功能定义接口(如IClick、IScroll),初期代码量增加。
对象管理复杂:需手动维护组件的创建、生命周期(如组合多个工具类时,需确保资源正确释放)。

组合与聚合的区别
合成复用原则中的 “组合 / 聚合” 是两种关联关系,核心区别在于生命周期是否绑定

组合(Composition):部分(如 Engine)的生命周期依赖于整体(如 Car),当 Car 销毁时,Engine 也随之销毁(如 “汽车包含发动机”)

┌─────────┐     组合     ┌─────────┐
│  整体   │◄────────────►│  部分   │
│ (Car)   │              │(Engine) │
└─────────┘              └─────────┘
(同生共死)

聚合(Aggregation):部分(如 Wheel)的生命周期独立于整体(如 Car),Car 销毁后,Wheel 可被其他对象使用(如 “汽车聚合车轮”)。

┌─────────┐     聚合     ┌─────────┐
│  整体   │◄────────────►│  部分   │
│ (Car)   │              │(Wheel)  │
└─────────┘              └─────────┘
(各自独立)

反例:过度继承导致的强耦合

// 父类:包含绘制和点击功能

open class BaseView : UIView {
   
   
    // 绘制逻辑
    open fun drawContent(canvas: Canvas) {
   
    ... }

    // 点击逻辑
    open fun handleClick() {
   
    ... }
}

// 子类:仅需绘制功能,但被迫继承点击逻辑
class DrawOnlyView : BaseView {
   
   
    override fun drawContent(canvas: Canvas) {
   
    ... } // 仅需重写绘制

    // 被迫继承handleClick(),即使不需要,若父类修改该方法,子类可能受影响
    override fun handleClick() {
   
    ... }
}

正例:组合实现功能复用

// 定义协议(相当于Kotlin的接口):分离功能
protocol Drawable {
   
   
    func draw(canvas: CGContext)
}

protocol Clickable {
   
   
    func onClick()
}

// 实现类:单一职责
class CircleDrawer: Drawable {
   
   
    func draw(canvas: CGContext) {
   
   
        // 处理圆形绘制的实现
    }
}

class ButtonClicker: Clickable {
   
   
    func onClick() {
   
   
        // 处理按钮点击的实现
    }
}

// 自定义View:通过组合复用功能,按需选择
class CustomView: UIView {
   
   
    // 持有协议实例(依赖抽象,而非具体实现)
    // 若修改为外部传入遵循对应协议的新实现(如SquareDrawer),则符合 开闭原则
    private let drawer: Drawable = CircleDrawer()  
    private let clicker: Clickable = ButtonClicker() 
    
    override func draw(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值