使用辅助函数保留了德墨忒尔定律的完整性(删除了两个点)?

2024-01-01

public House
{
    WeatherStation station;

    public float getTemp() {
        //Law of Demeter has been violated here
        return station.getThermometer().getTemperature();
    }
}

public House
{
    WeatherStation station;

    public float getTemp() {
        //Law of Demeter has been preserved?
        Thermometer thermometer = station.getThermometer();
        return getTempHelper(thermometer);
    }

    public float getTempHelper(Thermometer thermometer)
    {
        return thermometer.getTemperature();
    }
}

在上面的代码中,您可以看到两个不同的 House 类定义。两者都有 getTemp() 函数,第一个违反了德米特定律,但第二个保留了它(根据 Head First Design Patterns 书)。

问题是我不太明白为什么第二类保留德米特定律, getTemp() 函数仍然有 station.getThermometer() 调用,这(应该?)违反了德米特定律。 “仅使用一个点” - 我在维基百科上找到了这一点,这可能适用,但我仍然需要更详细的解释 - “特别是,一个对象应该避免调用由另一个方法返回的成员对象的方法”(维基)。

那么有人可以解释为什么第二个代码示例不违反法律吗?第二种方法与第一种方法的真正区别是什么?


我想关于这个主题可以进行很多讨论,但根据我的解释,德墨忒尔定律的目的是……

“你不想从车站得到温度计。你想从车站得到温度。”

从现实生活中的情况来考虑。你打电话给气象站,你不会问他们:“你大楼外面的温度计显示了什么?”你问他们:“现在的温度是多少?”他们在建筑物外部安装了温度计,这一事实与您无关。也许他们用指向窗户的红外激光代替了温度计。这对你来说并不重要。他们如何获得信息不是你关心的,你只需要这些信息。

所以,为此,你最终会得到这样的结果:

public House
{
    private WeatherStation _station;

    public House(WeatherStation station)
    {
        _station = station;
    }

    public float GetTemperature()
    {
        return _station.GetTemperature();
    }
}

public WeatherStation
{
    private Thermometer _thermometer;

    public WeatherStation(Thermometer thermometer)
    {
        _thermometer = thermometer;
    }

    public float GetTemperature()
    {
        return _thermometer.GetTemperature();
        // This can be replaced with another implementation, or any other
        // device which implements IThermometer, or a hard-coded test value, etc.
    }
}

这会导致多层嵌套,这看起来确实有点令人讨厌。但请记住,每个级别虽然目前被称为完全相同的东西,但含义略有不同。它不是really代码重复(如果重复的代码具有不同的含义)。你稍后可以用这样的东西打破链条:

public House
{
    private WeatherStation _station;

    public House(WeatherStation station)
    {
        _station = station;
    }

    public WeatherInfoDTO GetCurrentWeather()
    {
        var info = new WeatherInfoDTO();
        info.Temperature = _station.GetTemperature();
        //...
        return info;
    }
}

public WeatherInfoDTO
{
    //...
}

public WeatherStation
{
    private Thermometer _thermometer;

    public WeatherStation(Thermometer thermometer)
    {
        _thermometer = thermometer;
    }

    public float GetTemperature()
    {
        return _thermometer.GetTemperature();
        // This can be replaced with another implementation, or any other
        // device which implements IThermometer, or a hard-coded test value, etc.
    }

    //...
}

通过不对顶层进行硬编码来实现Thermometer您可以轻松重构以支持此类内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用辅助函数保留了德墨忒尔定律的完整性(删除了两个点)? 的相关文章

  • 计算字符串向量中连续数字的函数

    我想创建一个函数 它接受至少 1 个元素的字符串对象并包含数字 2 到 5 并确定是否存在至少 N 长度的连续数字 其中 N 是实际数字值 如果是 则返回字符串 true 否则返回字符串 false 例如 Input 555123 Outp
  • 进度状态报告模式

    我正在实现需要显示进程栏 或进度百分比 的长时间运行的进程 长时间运行的过程的整体逻辑很复杂 各种分页数据检索 因此 我最终在代码中的不同位置硬编码了大量百分比 在更新完成百分比时 什么被认为是最佳设计模式 我发现 JFace 周围使用的模
  • 如何在Java中实现复合模式?

    我想实现一个复合模式Java以便绘制软件开发组织图 因此 我们假设有多个项目经理和多个开发人员 每个开发人员都被分配给一位项目经理 并且每个开发人员都能够使用各种编程语言进行编码 项目经理领导开发人员并准确了解他们的工作量 我对这个设计模式
  • 如何将 sqldatareader 转换为 dto 列表?

    我刚刚开始将所有 ado net 代码从 asp net 页面移动到存储库 并为每个表创建 dto 手动 但现在我不知道将 sqldatareader 转换为我的列表的有效方法是什么dto 对象 例如 我的 dto 是 Customer 我
  • 如何在函数内 malloc 结构体数组?代码以其他方式工作

    我正在尝试创建一个函数来创建可变大小的二维函数数组 我正在使用以下代码 它本身似乎工作得很好 typedef struct Starter Properties int TypeB int TypeF int TypeW Randomize
  • 模块化大型 Grails 应用程序的最佳实践?

    我正在开发的 Grails 应用程序变得相当大 最好将其重构为几个模块 这样我们就不必每次都重新部署整个事情 将 Grails 应用程序拆分为多个模块的最佳实践是什么 特别是 我想创建一个域类 相关服务的包 并将其作为模块在应用程序中使用
  • 当需要不同数量和类型的参数时如何创建操作委托列表

    我们有一组大约两打的类 它们继承自具有抽象 Validate 方法的基类 当然 每个类都有不同的验证需求 但它们之间的不同组合需要规则 因此 正如您可以想象的那样 这导致了大量代码重复 例如 A 类需要规则 1 3 6 和 9B 类需要规则
  • 替换 R 中内置函数的定义?

    sparcl 包使用标准 stat 包中的 kmeans 函数 我想让它使用我自己的 kmeans 实现 一种方法是编辑 sparcl 包本身中的代码 我宁愿避免这种情况 因为它会很混乱 而且我不确定如何在 R 中安装编辑过的代码 不幸的是
  • 当前线程中的单例

    我的单身人士如下 public class CurrentSingleton private static CurrentSingleton uniqueInstance null private static object syncRoo
  • 如何编写从管道输入读取的 powershell 函数?

    SOLVED 以下是使用管道输入的函数 脚本的最简单示例 每个的行为都与通过管道传输到 echo cmdlet 相同 作为函数 Function Echo Pipe Begin Executes once before first item
  • MySQL中的字符串分割函数

    谁能告诉我如何在 mysql 中实现 split 函数 其行为类似于 Javascript split 我想要一个这样的功能 SELECT Split a b c d AS splitted 结果如下 splitted a b c d 有谁
  • Yegge 的原型模式示例如何处理实例变量?

    我喜欢史蒂夫 耶吉的原型模式示例 http steve yegge blogspot com 2008 10 universal design pattern html并决定快速制作一个概念验证示例 不过 我并没有真正考虑清楚 虽然它非常适
  • 如何重命名 bash 函数?

    我正在围绕另一个定义 bash 函数的软件包开发一些方便的包装器 我想用我自己的同名函数替换他们的 bash 函数 同时仍然能够从我的函数中运行他们的函数 换句话说 我需要重命名它们的函数 或者为其创建某种持久别名 当我创建同名函数时 该别
  • tbb:并行查找第一个元素

    我遇到了这个问题 查找列表中满足给定条件的第一个元素 不幸的是 该列表相当长 100 000 个元素 并且使用单个线程评估每个元素的条件总共需要大约 30 秒 有没有办法干净地并行化这个问题 我浏览了所有tbb模式 但找不到任何合适的 UP
  • 向 Python 函数添加属性的最佳方法

    以计算数学函数的 Python 函数为例 def func x a b c Return the value of the quadratic function ax 2 bx c return a x 2 b x c 假设我想以函数属性的
  • 如何从文件中获取整个函数

    好的 我现在正在逐行阅读一个文件 我知道文件中的每个函数名称 因为它是在 XML 文档中的其他位置定义的 应该是这样的 function function name 其中 function name 是函数的名称 我从 XML 文档中获取所
  • 如何在 Kotlin 中的数据类上实现空对象模式?

    我有一个 Kotlin 数据类 data class PaymentAccount val accountId Int val accountNumber String val title String 这就是我在 Java 中要做的事情
  • 行方向变异的有效方法

    我有两个数据框 dfUsers and purchases使用以下代码生成 set seed 1 library data table dfUsers lt data table user letters 1 5 startDate sam
  • 使用“const cv::Mat &”、“cv::Mat &”、“cv::Mat”或“const cv::Mat”作为函数参数的区别?

    我已经彻底搜索过 但没有找到一个简单的答案 传递 opencv 矩阵 cv Mat 作为函数的参数 我们传递一个智能指针 我们对函数内部的输入矩阵所做的任何更改也会改变函数范围之外的矩阵 我读到 通过将矩阵作为 const 引用传递 它不会
  • 空对象模式以避免空检查?

    最近 我遇到了空对象设计模式 我的同事说它可以用来消除整个代码中遇到的空指针检查 例如 假设 DAO 类返回有关 Customer 的信息 在名为 CustomerVO 的值对象中 我的主类应该提取名字和电子邮件 ID 并向客户发送电子邮件

随机推荐