如何提高代码的扩展性(6)

简介: 如何提高代码的扩展性(6)

1、场景举例分析


二、场景示例
下面就以我们传统行业的订单操作为例来说明下接口隔离的必要性。
1、胖接口
软件设计最初,我们的想法是相同功能的方法放在同一个接口里面,如下,所有订单的操作都放在订单接口IOrder里面。理论上来说,这貌似没错。我们来看看如何设计。
   public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
    }
刚开始只有销售订单,我们只需要实现这个接口就好了。
    public class SaleOrder:IOrder
    {
        public void Apply(object order)
        {
            throw new NotImplementedException();
        }
        public void Approve(object order)
        {
            throw new NotImplementedException();
        }
        public void End(object order)
        {
            throw new NotImplementedException();
        }
    }
后来,随着系统的不断扩展,我们需要加入生产订单,生产订单也有一些单独的接口方法,比如:排产、冻结、导入、导出等操作。于是我们向订单的接口里面继续加入这些方法。于是订单的接口变成这样:
    public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
        //订单下发操作
        void PlantProduct(object order);
     //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
我们生产订单的实现类如下
    //生产订单实现类
    public class ProduceOrder : IOrder
    {
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void Apply(object order)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void Approve(object order)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void End(object order)
        {
            throw new NotImplementedException();
        }
        public void PlantProduct(object order)
        {
            Console.WriteLine("订单下发排产");
        }
     public void Hold(object order)
        {
            Console.WriteLine("订单冻结");
        }
        public void Delete(object order)
        {
            Console.WriteLine("订单删除");
        }
        public void Import()
        {
            Console.WriteLine("订单导入");
        }
        public void Export()
        {
            Console.WriteLine("订单导出");
        }
    }
销售订单的实现类也要相应做修改
    //销售订单实现类
    public class SaleOrder:IOrder
    {
        public void Apply(object order)
        {
            Console.WriteLine("订单申请");
        }
        public void Approve(object order)
        {
            Console.WriteLine("订单审核处理");
        }
        public void End(object order)
        {
            Console.WriteLine("订单结束");
        }
        #region 对于销售订单无用的接口方法
        public void PlantProduct(object order)
        {
            throw new NotImplementedException();
        }
     public void Hold(object order)
        {
            throw new NotImplementedException();
        }
        public void Delete(object order)
        {
            throw new NotImplementedException();
        }
        public void Import()
        {
            throw new NotImplementedException();
        }
        public void Export()
        {
            throw new NotImplementedException();
        } 
        #endregion
    }
需求做完了,上线正常运行。貌似问题也不大。系统运行一段时间之后,新的需求变更来了,要求生成订单需要一个订单撤销排产的功能,那么我们的接口是不是就得增加一个订单撤排的接口方法CancelProduct。于是乎接口变成这样:
public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
        //订单下发操作
        void PlantProduct(object order);
        //订单撤排操作
        void CancelProduct(object order);
        //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
这个时候问题就来了,我们的生产订单只要实现这个撤销的接口貌似就OK了,但是我们的销售订单呢,本来销售订单这一块我们不想做任何的变更,可是由于我们IOrder接口里面增加了一个方法,销售订单的实现类是不是也必须要实现一个无效的接口方法?这就是我们常说的“胖接口”导致的问题。由于接口过“胖”,每一个实现类依赖了它们不需要的接口,使得层与层之间的耦合度增加,结果导致了不需要的接口发生变化时,实现类也不得不相应的发生改变。这里就凸显了我们接口隔离原则的必要性,下面我们就来看看如何通过接口隔离来解决上述问题。
2、接口隔离
我们将IOrder接口分成两个接口来设计
    //删除订单接口
    public interface IProductOrder
    {
        //订单下发操作
        void PlantProduct(object order);
        //订单撤排操作
        void CancelProduct(object order);
        //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
    //销售订单接口
    public interface ISaleOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
    }
对应的实现类只需要实现自己需要的接口即可
    //生产订单实现类
    public class ProduceOrder : IProductOrder
    {
        public void PlantProduct(object order)
        {
            Console.WriteLine("订单下发排产");
        }
        public void CancelProduct(object order)
        {
            Console.WriteLine("订单撤排");
        }
        public void Hold(object order)
        {
            Console.WriteLine("订单冻结");
        }
        public void Delete(object order)
        {
            Console.WriteLine("订单删除");
        }
        public void Import()
        {
            Console.WriteLine("订单导入");
        }
        public void Export()
        {
            Console.WriteLine("订单导出");
        }
    }
    //销售订单实现类
    public class SaleOrder : ISaleOrder
    {
        public void Apply(object order)
        {
            Console.WriteLine("订单申请");
        }
        public void Approve(object order)
        {
            Console.WriteLine("订单审核处理");
        }
        public void End(object order)
        {
            Console.WriteLine("订单结束");
        }
    }


这样设计就能完美解决上述“胖接口”导致的问题,如果需要增加订单操作,只需要在对应的接口和实现类上面修改即可,这样就不存在依赖不需要接口的情况。通过这种设计,降低了单个接口的复杂度,使得接口的“内聚性”更高,“耦合性”更低。由此可以看出接口隔离原则的必要性。


另:

有称六大设计原则:+迪米特法则。


迪米特法则的定义是:只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。


举例:明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则,其类图如图 所示。


image.png

相关文章
|
5天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
2495 17
|
6天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1088 3
|
云安全 安全 网络安全
|
5天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
6天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
18天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3242 51
|
12天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
2120 2
|
11天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。

热门文章

最新文章