【设计模式】设计原则之迪米特法则(LoD: Law of Demeter)

迪米特法则也称为"最少知识原则",是降低代码耦合度的关键设计原则。它通过限制对象间的交互范围,提高系统的模块化、可维护性和可测试性。

核心定义

一个对象应当对其他对象有最少的了解:只与直接的朋友通信,不与"陌生人"说话。​

三大核心规则

  1. 有限范围规则​:对象的方法只能访问

    • 对象自身的属性
    • 方法参数传入的对象
    • 方法内创建的对象
    • 对象的直接组件对象
  2. 禁止链式调用​:避免出现长链式访问
    a.getB().getC().doSomething()

  3. 封装控制原则​:不让外部直接操作内部组件状态

C++ 代码示例

违反 LoD 的典型例子
class Engine {
public:
    void start() { /* 启动引擎 */ }
};

class CarDoor {
public:
    void open() { /* 开门 */ }
};

// 错误实现:暴露内部组件
class Car {
public:
    Engine* getEngine() { return &engine_; }   // ❌ 暴露内部组件
    CarDoor* getDoor() { return &door_; }      // ❌ 暴露内部组件
    
    void operate() {
        // ❌ 链式调用:Car→Engine
        getEngine()->start();
    }

private:
    Engine engine_;
    CarDoor door_;
};

// 客户端代码违反 LoD
void clientCode() {
    Car myCar;
    
    // 🚫 直接访问内部组件(危险!)
    myCar.getDoor()->open();
    
    // 🚫 深层链式调用
    myCar.getEngine()->start();
}
遵循 LoD 的重构实现
class Car {
public:
    // ✅ 封装内部操作
    void unlock() { door_.open(); }
    void start() { engine_.start(); }
    
    // ✅ 禁止外部访问内部组件
    // 不再提供 getEngine()/getDoor() 方法

private:
    Engine engine_;
    CarDoor door_;
};

// 客户端安全使用
void clientCode() {
    Car myCar;
    myCar.unlock(); // ✅ 只与直接朋友通信
    myCar.start();  // ✅ 通过封装方法控制
}

深度应用场景

1. 多层嵌套对象访问
// 🚫 违反 LoD:三层链式访问
class A {
public:
    B* getB() { return b_; } // ❌ 暴露内部组件
private:
    B* b_;
};

class B {
public:
    C* getC() { return c_; } // ❌ 暴露内部组件
private:
    C* c_;
};

// 客户端问题代码
a.getB()->getC()->doAction();

// ✅ 重构方案:中间层封装
class A {
public:
    void performAction() { // 封装访问链
        b_->getC()->doAction();
    }
};
2. STL 容器封装
class Library {
public:
    // 🚫 违反 LoD:返回内部容器引用
    std::vector<Book>& getBooks() { return books_; }
    
    // ✅ 遵循 LoD:封装访问方法
    void addBook(const Book& book) {
        books_.push_back(book);
    }
    
    Book findBook(const std::string& isbn) const {
        auto it = std::find_if(books_.begin(), books_.end(),
            [&](const Book& b) { return b.isbn == isbn; });
        return (it != books_.end()) ? *it : Book{};
    }

private:
    std::vector<Book> books_;
};

设计模式中的应用

1. 外观模式(Facade)
// 复杂子系统
class CPU { public: void execute() {} };
class Memory { public: void load() {} };
class HardDrive { public: void read() {} };

// ✅ Facade 封装
class ComputerFacade {
public:
    void start() {
        memory_.load(0, hd_.read(BOOT_SECTOR));
        cpu_.execute(0, 100);
    }
    
private:
    CPU cpu_;
    Memory memory_;
    HardDrive hd_;
};

// 客户端只需与 Facade 交互
ComputerFacade computer;
computer.start(); // 隐藏了内部组件交互
2. 中介者模式(Mediator)
class UIControl {
protected:
    Mediator* mediator_;
public:
    UIControl(Mediator* m) : mediator_(m) {}
};

class Button : public UIControl {
    using UIControl::UIControl;
    void click() {
        mediator_->notify(this, "click"); // 仅与中介者通信
    }
};

class Mediator {
    void notify(UIControl* sender, const std::string& event) {
        // 处理控件间交互逻辑
    }
};

C++ 特殊优化策略

1. 方法返回值优化
class ReportGenerator {
public:
    // ✅ 返回值而非引用/指针
    Report generateReport() {
        Report report;
        // ...填充报告数据
        return report; // RVO/NRVO 避免拷贝
    }
};
2. 移动语义支持
class DataProcessor {
public:
    // ✅ 高效返回大型对象
    BigData process() {
        BigData data;
        // ...处理数据
        return data; // 启用移动语义
    }
};
3. 返回智能指针的封装
class ResourceManager {
public:
    // ✅ 封装资源访问
    void useResource() {
        auto resource = getResource();
        resource->operate();
    }

private:
    std::unique_ptr<Resource> getResource() {
        return std::make_unique<ResourceImpl>();
    }
};

性能与设计平衡策略

场景推荐方案性能影响
高频调用的简单数据访问适度放宽 LoD (直接访问)⚡ 最优性能
跨模块边界交互严格遵守 LoD (完全封装)🔒 最佳封装性
大型数据集合访问提供迭代器/范围访问⚖️ 平衡封装和效率
组件层级交互使用中介者/外观模式🛡️ 最佳解耦效果

LoD 实施检查清单

  1. 是否避免了超过一层的方法调用链?

    // ❌ 禁止写法
    objA.getB().getC().doAction();
    
    // ✅ 允许写法
    objA.executeAction();
  2. 是否禁止返回内部组件的引用/指针?

    // ❌ 非法暴露
    const std::vector<Item>& getItems();
    
    // ✅ 安全封装
    const Item& getItem(size_t index);
    void forEachItem(std::function<void(const Item&)> callback);
  3. 是否将相关操作封装在当前对象中?

    // ❌ 分散在客户端
    void clientCode() {
        if (car.getDoor().isLocked()) {
            car.getDoor().unlock();
        }
    }
    
    // ✅ 对象自我管理
    class Car {
        void enter() {
            if (door_.isLocked()) {
                door_.unlock();
            }
        }
    };
  4. 是否避免了在参数中传递复杂结构?

    // ❌ 暴露内部结构
    void printDepartmentInfo(Employee& e) {
        cout << e.getDepartment().getName();
    }
    
    // ✅ 对象提供完整接口
    void printDepartmentInfo(Employee& e) {
        cout << e.getDepartmentName();
    }

LoD 与其它原则的协同

原则协同效果
SRP共同降低类复杂度,提高内聚性
OCP封装变化点,减少修改波及范围
ISP精细接口自然满足 LoD 的"最少知识"要求
DIP依赖抽象避免知晓具体实现细节

迪米特法则在C++系统设计中可降低50%+的模块间耦合(根据工业界数据统计)。尤其在大型系统、安全关键系统(如自动驾驶、航空航天)中,遵循LoD可显著提高代码可靠性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浩瀚之水_csdn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值