06.迪米特法则(Demeter Principle)

news2024/9/23 13:23:46

明 嘉靖四十年 江南织造总局
小黄门唯唯诺诺的听完了镇守太监杨金水的训斥,赶忙回答:“知道了,干爹!”
“知道什么?!!”
杨金水打断了他的话,眼神突然变得凌厉起来:
“有些事情,不上秤没有四两重,上秤了,一千斤都挡不住。”

一言

迪米特法则,即最少知道原则。其它类的方法你想怎么实现都可以,不要在我引用的地方乱显摆。


概述

哲学是最接近世界本质的学科。理科生应该经常读到这样的论断:“生物的本质是化学,化学的本质是物理,物理的本质是数学,数学的本质是哲学。”
的确,从表现到反应、到作用、最后又到了关系。随着年龄的增长和阅历的积累,我们会越来越明晰的发现,无论是在软件设计还是日常生活,你能把事物关系处理的越好,整个体系就会越稳健。编程如此,人生亦然。

《哈利波特》中多方势力的角逐可以说精彩非凡。霍格沃兹、魔法部、食死徒、凤凰社…每个角色都给人留下了深刻的印象。错综复杂的关系使得正与邪之间的斗争变得充满变数。比如在小说中,魔法部名为司法部门,其中成员却鱼龙混杂,既有像亚瑟·韦斯莱一样心怀正义的凤凰社成员,也有背弃初心屈服于伏地魔的食死徒。
在这里插入图片描述

当面对复杂的对象关系,我们往往很难意识到无规则调用带来的风险。迪米特法则正是用于规范对象关系的一句箴言。它要求一个对象应该对其它对象保持最少的了解,也就是我们常说的低耦合,类与类之间的关系越密切,耦合度也就越大。
说到这里大家也许会想起我之前在说OCP原则时举得例子,工具方法无差别的被几百个应用模块引用是否合理?

我们不妨再进一步简化它的定义:每个对象应该只与他的直接朋友(建立关系)通信。

什么是直接朋友

每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。而耦合的方式很多:依赖,关联,组合,聚合等都是耦合关系。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。

也就是说,陌生的类最好不要以局部变量的形式出现在类的内部


欢迎来到魔法世界

我觉得说了上面一大通,太抽象了。按我的风格,我们还是从一个有趣的情景出发来拆解下迪米特法则到底是个什么东西。

不好,他们抓住了韦斯莱

在这里插入图片描述

魔法部被邪恶势力食死徒完全的渗透了,现在他们想要得到凤凰社所有成员的名单和这些凤凰社成员的秘密。食死徒们想了一个堂而皇之的借口,成立魔法部成员管理委员会,核查所有魔法部成员的名单,同时核查凤凰社成员的名单。
对于凤凰社来说,被食死徒们知道了名单并不可怕,重要的是不能泄露凤凰社成员的秘密。
亚瑟·韦斯莱既是凤凰社成员又是魔法部成员,自然成为了食死徒的首要目标。
卑鄙的食死徒终于还是对亚瑟韦斯莱用了吐真剂。

public class MajicWorld {
    public static void main(String[] args) {
        MinistryOfMagicManager touch = new MinistryOfMagicManager();
        touch.printAllGuys(new ArthurWeasley());
    }

    public static List<PhoenixSociety> initPs(){
        List<PhoenixSociety> psList = new ArrayList<>();
        PhoenixSociety p1 = new PhoenixSociety();
        p1.setName("小天狼星 布莱克");
        p1.setSecret("凤凰社的人我都认识");
        psList.add(p1);
        PhoenixSociety p2 = new PhoenixSociety();
        p2.setName("莱姆斯 卢平");
        p2.setSecret("我可以变成狼人");
        psList.add(p2);
        PhoenixSociety p3 = new PhoenixSociety();
        p3.setName("西弗勒斯 斯内普");
        p3.setSecret("我深爱着莉莉,她的儿子是我的软肋");
        psList.add(p3);
        PhoenixSociety p4 = new PhoenixSociety();
        p4.setName("尼法朵拉 唐克斯");
        p4.setSecret("死亡圣器的秘密可能是真的");
        psList.add(p4);
        return psList;
    }

    public static List<MinistryOfMagic> initMajicMembers(){
        List<MinistryOfMagic> psList = new ArrayList<>();
        MinistryOfMagic p1 = new MinistryOfMagic();
        p1.setName("尤里克·甘普");
        psList.add(p1);
        MinistryOfMagic p2 = new MinistryOfMagic();
        p2.setName("巴蒂·克劳奇");;
        psList.add(p2);
        MinistryOfMagic p3 = new MinistryOfMagic();
        p3.setName("康奈利·福吉");
        psList.add(p3);
        MinistryOfMagic p4 = new MinistryOfMagic();
        p4.setName("卢多·巴格曼");
        psList.add(p4);
        return psList;
    }
}

//魔法部成员
class MinistryOfMagic{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

//凤凰社成员
class PhoenixSociety{
    private String name;
    private String secret;//秘密

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }
}

//亚瑟韦斯莱(罗恩的爸爸),他知道部分凤凰社成员的名单
class ArthurWeasley{
    public List<PhoenixSociety> sayMembersOfPhoenixSociety(){
        List<PhoenixSociety> psList = MajicWorld.initPs();
        return psList;
    }
}

//魔法部成员管理委员会
//这个部门应该只可以管理魔法部成员,以及亚瑟韦斯莱,因为亚瑟既是魔法部成员也是凤凰社成员
//但是凤凰社成员直接暴露在魔法部是很危险的
class MinistryOfMagicManager{
    //返回魔法部的所有成员
    public List<MinistryOfMagic> getList(){
        return MajicWorld.initMajicMembers();
    }

    //输出魔法部成员和凤凰社成员
    public void printAllGuys(ArthurWeasley arthur){
        //给韦斯莱灌了吐真剂
        List<PhoenixSociety> pss = arthur.sayMembersOfPhoenixSociety();
        pss.forEach(e-> System.out.println("我是凤凰社成员:"+e.getName()+",我的秘密是:"+e.getSecret()));

        System.out.println("-------------------------------------");
        //获取全部魔法部成员
        List<MinistryOfMagic> list = this.getList();
        list.forEach(e-> System.out.println("魔法部成员:"+e.getName()));
    }
}

下面我们来分析一下这段代码的问题,
魔法部成员管理委员会类(MinistryOfMagicManager)这个类的直接朋友应该是 魔法部成员类(MinistryOfMagic )和 亚瑟·韦斯莱类(ArthurWeasley),因为只有这两个类属于魔法部,而凤凰社成员并不都是魔法部的,所以凤凰社成员类(PhoenixSociety)并不应该出现在这个类中,这违反了迪米特法则。
因为对于亚瑟·韦斯莱(ArthurWeasley)这个类的设计缺陷,直接导致了食死徒可以通过魔法部成员管理委员会类(MinistryOfMagicManager)这个类获得凤凰社成员类(PhoenixSociety)的实现细节,进而盗取出凤凰社的秘密。
在这里插入图片描述

韦斯莱是个意志坚定的人,他不会出卖我们

在这里插入图片描述

我们已经看到了,问题出在了亚瑟·韦斯莱(ArthurWeasley)这个类的设计上。只要让他遵循迪米特法则,处理好实现细节就能规避掉耦合度提高的问题。

//亚瑟韦斯莱(罗恩的爸爸),他知道部分凤凰社成员的名单
class ArthurWeasley{
    private List<PhoenixSociety> sayMembersOfPhoenixSociety(){
        List<PhoenixSociety> psList = MajicWorldUnderDemeterPrinciple.initPs();
        return psList;
    }

    public void printPs(){
        List<PhoenixSociety> phoenixSocieties = this.sayMembersOfPhoenixSociety();
        phoenixSocieties.forEach(e-> System.out.println("我是凤凰社成员:"+e.getName()+"。罪恶的食死徒,即使你对韦斯莱用了吐真剂也别想知道我的秘密。"));
    }
}

而当魔法部成员管理委员会类(MinistryOfMagicManager)再一次对韦斯莱用“吐真剂”时,由于韦斯莱将凤凰社成员类(PhoenixSociety)的引用完全私有,外部调用即便想要盗取凤凰社成员类(PhoenixSociety)的实现细节也无从下手。他们只能通过公共的方法printPs获得名单,而对于秘密则还是一无所知。

class MinistryOfMagicManager{
    //返回魔法部的所有成员
    public List<MinistryOfMagic> getList(){
        return MajicWorldUnderDemeterPrinciple.initMajicMembers();
    }

    //输出魔法部成员和凤凰社成员
    public void printAllGuys(ArthurWeasley arthur){
        //给韦斯莱灌了吐真剂
        arthur.printPs();

        System.out.println("-------------------------------------");
        //获取全部魔法部成员
        List<MinistryOfMagic> list = this.getList();
        list.forEach(e-> System.out.println("魔法部成员:"+e.getName()));

    }
}

在这里插入图片描述
我们通过迪米特法则的优化设计挫败了食死徒的阴谋。


从设计的角度来看,迪米特法则的核心是降低类与类之间的耦合,减少了不必要的依赖。但是需要注意的是,迪米特法则只是要求降低类间(对象间)耦合关系,并不是要求完全没有依赖关系。这其实是需要根据业务慎重考量的部分。
比如,我现在针对上面的实现加一个需求,编写一个凤凰社管理办公室类,用来记录所有凤凰社成员的秘密(field:secret),这个类是不是就必须要有相应的耦合关系呢?
软件设计的几个原则在实际应用中如何权衡,也是个哲学问题。


关注我,共同进步,每周至少一更。——Wayne

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1311309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业计算机服务器中了halo勒索病毒如何解密,halo勒索病毒恢复流程

网络技术的不断发展与应用&#xff0c;为企业的生产运营提供了极大便利&#xff0c;越来越多的企业使用数据库存储企业的重要数据&#xff0c;方便工作与生产&#xff0c;但网络是一把双刃剑&#xff0c;网络安全威胁一直存在&#xff0c;并且网络威胁的手段也在不断升级。在本…

我的隐私计算学习——匿踪查询

笔记内容来自多本书籍、学术资料、白皮书及ChatGPT等工具&#xff0c;经由自己阅读后整理而成。 &#xff08;一&#xff09;PIR的介绍 ​ 匿踪查询&#xff0c;即隐私信息检索&#xff08;Private InformationRetrieval&#xff0c;PIR&#xff09;&#xff0c;是安全多方计算…

C# OpenVINO 直接读取百度模型实现印章检测

目录 效果 模型信息 项目 代码 下载 其他 C# OpenVINO 直接读取百度模型实现印章检测 效果 模型信息 Inputs ------------------------- name&#xff1a;scale_factor tensor&#xff1a;F32[?, 2] name&#xff1a;image tensor&#xff1a;F32[?, 3, 608, 608] …

Windows更改远程桌面端口并添加防火墙入站规则

1.运行 快捷键winR组合键&#xff0c;win就是键盘上的windows系统图标键。 2.打开注册表 Regedit&#xff0c;在对话框中输入regedit命令&#xff0c;然后回车 3.打开注册表&#xff0c;输入命令后&#xff0c;会打开系统的注册表&#xff0c;左边是目录栏&#xff0c;右边是…

基于STM32的智能小区环境监测

一、概述 本系统应用STM32F407VET6单片机为控制处理器&#xff0c;加上外设备组成单片机最小系统。配以输入输出部分&#xff0c;通过采集温湿度、甲醛、PM2.5等数据在LCD液晶上显示&#xff0c;内加单独时钟晶振电路&#xff0c;保护断电后时间参数不变&#xff0c;外接5v电源…

QGIS 加载在线XYZ地图图层

QGIS 加载在线XYZ地图图层 定义并添加必应XYZ图层 Go to Layer > Add Layer > Add XYZ Layer…Click NewName as BingMaps(as you wish)URL as http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g1click OkSelect XYZ Connections as Bing Maps(Which you creat…

C++之获取变量信息名称、类型typeid

摘要 对于C工程量级比较庞大的代码&#xff0c;代码中的变量、类、函数、结构体的识别都是一件让人头疼的事情&#xff0c;一方面代码越写越多&#xff0c;内容越来越丰富&#xff0c;但是没有办法对已有的代码框架进行高度的整合提炼&#xff1b;另一方面对新人逐渐不友好&am…

python 协程

python 协程 协程为什么需要协程&#xff1f;协程与子线程的区别协程的工作原理协程的优缺点协程优点协程缺点 协程的实现yield 关键字greenlet 模块gevent 模块Pool 限制并发 协程 协程又称微线程&#xff0c;英文名coroutine。协程是用户态的一种轻量级线程&#xff0c;是由…

Visual Studio开发环境的搭建

1.引言 Visual Studio是微软公司开发的一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员进行各种编程任务&#xff0c;包括设计、开发、测试、调试和部署应用程序。典型功能包括&#xff1a; 代码编辑器。提供高效、智能的代码编辑器&#x…

一文读懂FastAPI:Python 开发者的福音

FastAPI是一个基于Python的现代化Web框架&#xff0c;它提供了快速、简单和高性能的方式来构建API。 它结合了Python的静态类型检查和自动化文档生成的功能&#xff0c;使得开发API变得更加容易和高效。 下面将介绍如何使用FastAPI快速开发接口&#xff0c;并且利用自动生成的…

Red Hat Satellite - 为主机配置可使用的内容(存储库),注册主机并安装软件包

《OpenShift / RHEL / DevSecOps 汇总目录》 请先根据《Red Hat Satellite - 导入订阅清单》一文完成向 Red Hat Satellite 导入分配的订阅订单。 本文中的相关概念请参见《Red Hat Satellite - 核心概念篇》。 文章目录 配置 Repository 并同步配置生命周期的环境路径配置内容…

死锁的概念

死锁&#xff08;Deadlock&#xff09;、饥饿&#xff08;Starvation&#xff09;和死循环&#xff08;Infinite Loop&#xff09;是计算机科学中与并发和并行处理相关的三个概念&#xff0c;它们描述了不同类型的问题和情况。 死锁&#xff08;Deadlock&#xff09;: 定义: 死…

优先考虑静态成员类

在Java中&#xff0c;静态成员类&#xff08;static nested class&#xff09;是一种嵌套在另一个类中的类&#xff0c;且被声明为静态。静态成员类不依赖于外部类的实例&#xff0c;可以直接通过外部类的类名来访问。 优先考虑使用静态成员类的情况通常是当这个类与外部类的实…

IC卡卡号修改UID卡CUID卡物理卡号修改考勤工号修改

普通M1卡的物理卡号是锁死的&#xff0c;UID卡、CUID卡、FUID卡是特殊的M1卡&#xff0c;他们的物理卡号是可以修改的。考勤卡、门禁等读取到的IC卡卡号是这样的0136098153&#xff0c;10位卡号&#xff0c;这个卡号是随机的&#xff0c;不连续的&#xff0c;没有规律&#xff…

纯干货|聊一聊大促活动背后的技术:火山引擎边缘云CDN/DCDN/GA

12月12日&#xff0c;“抖音商城双12好物节”正式结束。据了解&#xff0c;双12期间&#xff0c;抖音电商推出了超值购、秒杀等多个优价频道和多个类目的主题榜单&#xff0c;让有消费需求的用户更高效地发现高性价比好物。除了货架场景&#xff0c;“抖音商城双12好物节”还发…

基于ssm校园资讯推荐系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园资讯推荐系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

31、应急响应——Windows

文章目录 一、账户排查1.1 登录服务器的途径1.2 弱口令1.3 可疑账号 二、网络排查三、进程排查四、注册表排查五、内存分析 一、账户排查 1.1 登录服务器的途径 3389smb 445httpftp数据库中间件 1.2 弱口令 弱口令途径&#xff1a;3389、smb 445、http、ftp、数据库、中间件…

C# 如何控制多线程同步执行

写在前面 使用Task类来控制多线程的同步执行&#xff0c;可应用于多任务分发执行后&#xff0c;再做归并处理。Tas既拥有线程池的优点&#xff0c;同时也解决了使用ThreadPool不易控制的弊端&#xff1b;可以非常简便并可靠地实现多线程的顺序执行。 代码实现 public class …

Qt 文字描边(基础篇)

项目中有时需要文字描边的功能 1.基础的绘制文字 使用drawtext处理 void MainWindow::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);painter.setRenderHint(QPainter::SmoothPixmapTransform, true);painte…

宏基因组学中如何计算分箱结果bins(基因组)的丰度?

1、基于metawrap环境计算bin丰度(推荐) MetaWRAp&#xff08;Metagenomic Workflow for Assembly, binning, and annotation&#xff09;是一个用于处理宏基因组学数据的工具&#xff0c;包括元组装、分箱&#xff08;binning&#xff09;、基因组注释等功能。要基于 MetaWRAp …