当前位置:首页 > 服务端 > C#软件设计——小话设计模式原则之:接口隔离原则ISP

C#软件设计——小话设计模式原则之:接口隔离原则ISP

2022年09月16日 16:28:35服务端4

前言:有朋友问我,设计模式原则这些东西在园子里都讨论烂了,一搜一大把的资料,还花这么大力气去整这个干嘛。博主不得不承认,园子里确实很多这方面的文章,并且不乏出色的博文。博主的想法是,既然要完善知识体系,就不能半途而废。今天就来看看设计模式原则的另一个:接口隔离原则。

软件设计原则系列文章索引

一、原理介绍

1、官方定义

接口隔离原则,英文缩写ISP,全称Interface Segregation Principle。

原始定义:Clients should not be forced to depend upon interfaces that they don't use,还有一种定义是The dependency of one class to another one should depend on the smallest possible interface。

官方翻译:其一是不应该强行要求客户端依赖于它们不用的接口;其二是类之间的依赖应该建立在最小的接口上面。简单点说,客户端需要什么功能,就提供什么接口,对于客户端不需要的接口不应该强行要求其依赖;类之间的依赖应该建立在最小的接口上面,这里最小的粒度取决于单一职责原则的划分。

2、自己理解

2.1、原理解释

  • 不应该强行要求客户端依赖于它们不用的接口。语句很好理解,即客户端需要什么接口,就依赖什么接口,不需要的就不依赖。那么我们反过来说,如果客户端依赖了它们不需要的接口,那么这些客户端程序就面临不需要的接口变更引起的客户端变更的风险,这样就会增加客户端和接口之间的耦合程度,显然与“高内聚、低耦合”的思想相矛盾。
  • 类之间的依赖应该建立在最小的接口上面。何为最小的接口,即能够满足项目需求的相似功能作为一个接口,这样设计主要就是为了“高内聚”。那么我们如何设计最小的接口呢?那就要说说粒度的划分了,粒度细化的程度取决于我们上一章讲的的单一职责原则里面接口划分的粒度。从这一点来说,接口隔离和单一职责两个原则有一定的相似性。

2.2、接口隔离原则和单一职责原则

从功能上来看,接口隔离和单一职责两个原则具有一定的相似性。其实如果我们仔细想想还是有区别的。

(1)从原则约束的侧重点来说,接口隔离原则更关注的是接口依赖程度的隔离,更加关注接口的“高内聚”;而单一职责原则更加注重的是接口职责的划分。

(2)从接口的细化程度来说,单一职责原则对接口的划分更加精细,而接口隔离原则注重的是相同功能的接口的隔离。接口隔离里面的最小接口有时可以是多个单一职责的公共接口。

(3)单一职责原则更加偏向对业务的约束,接口隔离原则更加偏向设计架构的约束。这个应该好理解,职责是根据业务功能来划分的,所以单一原则更加偏向业务;而接口隔离更多是为了“高内聚”,偏向架构的设计。

二、场景示例

下面就以订单的操作为例来说明下接口隔离的必要性。

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("订单结束");
        }
    }

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

三、总结

通过以上订单功能的优化,我们看到了接口隔离原则的必要性,当然,关于接口隔离原则和单一职责原则的细节我们也不必过多追究,不管何种原则,能解决我们的设计问题就是好的原则、我们必须遵守的原则。欢迎园友拍砖斧正。如果园友们觉得本文对你有帮助,请帮忙推荐,博主将继续努力~~

 

作者:懒得安分
来源链接:https://www.cnblogs.com/landeanfen/p/5266209.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/server/42012.html

标签: 设计模式
分享给朋友:

“C#软件设计——小话设计模式原则之:接口隔离原则ISP” 的相关文章

常用设计模式系列(五)—原型模式

常用设计模式系列(五)—原型模式

一、前言 各位朋友大家好,经过几天的努力,我已经讲解了常用设计模式其中的四种,分别是简单工厂、工厂方法、抽象工厂、建造者模式,正在想着下一遍写哪个模式的时候,有个朋友先说他想先看看原型模式,说想看看原型模式是如何运行的,然后我给这个朋友讲了个故事:“从前有个老铁得了个病,听说还挺严重的,后来...

数据库相关(JDBC,存储过程,以及大文本数据处理,mvc设计模式)

数据库相关(JDBC,存储过程,以及大文本数据处理,mvc设计模式)

目录 1.jdbc总结(模板、八股文): 2.CallableStatement:调用 存储过程、存储函数...

炒冷饭系列:设计模式 装饰模式

炒冷饭系列:设计模式 装饰模式

炒冷饭系列:设计模式 装饰模式 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 钢琴弹得好是艺术,文章写的好也是艺术。 一、什么是装...

炒冷饭系列:设计模式 抽象工厂模式

炒冷饭系列:设计模式 抽象工厂模式

炒冷饭系列:设计模式 抽象工厂模式 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 亲爱我,孝何难;亲恶我,孝方贤。 一、什么是抽象...

IOS设计模式之三:MVC模式

IOS设计模式之三:MVC模式

提到ios中的mvc不得不提2011秋季斯坦福课程的老头,他的iphone开发公开课是所有描述ios中mvc模式最为准确并且最为浅显易懂的。 模型-视图-控制器 这个模式其实应该叫做MCV,用控制器把model与view隔开才对,也就是model与view互相不知道对方的存...

Java设计模式-工厂模式

Java设计模式-工厂模式

Java设计模式-工厂模式 什么是工厂模式? 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创...

Java设计模式面试题及答案(持续更新。。。)

Java面试题及答案(2022版),每道都是认真筛选出的高频面试题,助力大家能找到满意的工作! Java设计模式面试题及答案 下载链接:全部面试题及答案PDF 1.请列举出在 JDK 中几个常用的设计模式? 单例模式(Single...

2021Java高级面试题!java设计模式场景

2021Java高级面试题!java设计模式场景

一、掀起Spring的盖头来 Spring框架的由来 Spring框架概述 二、Spring的IoC容器 重头开始认识loC的基本概念:(构造方法注入+scttcr方法注入+接口注入) 运筹帷幄的秘密...

单例设计模式线程安全问题

单例设计模式线程安全问题 懒汉式 class Lazy { private Lazy(){ System.out.println("test Lazy"); } private static Lazy lazy=null;...

常用设计模式

常用设计模式

设计模式 从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联和组合关系的充分理解。 正确使用设计模式具有一下优点: 1、...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。