zoukankan      html  css  js  c++  java
  • 第三节:接口隔离原则、迪米特法则、组合聚合原则

    一. 接口隔离原则

    1. 定义

     一个类对另一个类的依赖应该建立在最小的接口上,不应该依赖他不需要的接口。

     通俗的说:要为每个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

    与单一职责原则的区别:

    (1). 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。

    (2). 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。

    2. 优点

      接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 优点:

     (1). 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

     (2). 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。

     (3). 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。

     (4). 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。

     (5). 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。

    3. 实现方法和案例

    (1). 实现方法

     A. 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。

     B. 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。

     C. 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。

     D. 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

    (2). 案例

     在成绩管理系统中,会有很多业务,这里拆分出来多个接口,分别是:输入模块接口、统计模块接口、打印模块接口,需要哪个接口就去实现哪个接口。

       /// <summary>
       /// 基础模块接口 
       /// </summary>
        public interface IBasicModel
        {
            void insert();
            void delete();
            void modify();
        }
        /// <summary>
        /// 统计模块接口
        /// </summary>
        public interface ICountModule
        {
            void countTotalScore();
            void countAverage();
        }
        /// <summary>
        /// 打印模块接口
        /// </summary>
        public interface IPrintModule
        {
            void printStuInfo();
            void queryStuInfo();
        }

    二. 迪米特法则

    1. 定义

     又叫:最小知道原则。

     其含义:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。 通俗的来说:只与你的直接朋友交谈,不跟“陌生人”说话。

       目的:降低类之间的耦合度,提高模块的相对独立性。

    进一步解析:

     (1). 从依赖者的角度来说,只依赖应该依赖的对象。

     (2). 从被依赖者的角度说,只暴露应该暴露的方法。

    2. 优点

     (1). 降低了类之间的耦合度,提高了模块的相对独立性。

     (2). 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。

    同样也有弊端:

     过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。

    3. 实现方法和案例

    (1). 实现方法

     A. 在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。

     B. 在类的结构设计上,尽量降低类成员的访问权限。

     C. 在类的设计上,优先考虑将一个类设置成不变类。

     D. 在对其他类的引用上,将引用其他对象的次数降到最低。

     E. 不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。

     F. 谨慎使用序列化(Serializable)功能。

    (2). 案例

     明星 ----- 经纪人 ------ 粉丝、媒体;  明星不直接和粉丝、媒体打交道,都是通过经纪人来打交道。

    明星和粉丝、媒体类

       /// <summary>
        /// 粉丝类
        /// </summary>
        public class Fans
        {
            private String name;
            public Fans(String name)
            {
                this.name = name;
            }
            public String getName()
            {
                return name;
            }
        }
        /// <summary>
        /// 媒体公司类
        /// </summary>
        public class Company
        {
            private String name;
            public Company(String name)
            {
                this.name = name;
            }
            public String getName()
            {
                return name;
            }
        }
       /// <summary>
        /// 明星类
        /// </summary>
        public class Star
        {
            private String name;
            public Star(String name)
            {
                this.name = name;
            }
            public String getName()
            {
                return name;
            }
        }
    View Code

    经纪人

    /// <summary>
        /// 经纪人类
        /// </summary>
        public class Agent
        {
            private Star myStar;
            private Fans myFans;
            private Company myCompany;
            public void setStar(Star myStar)
            {
                this.myStar = myStar;
            }
            public void setFans(Fans myFans)
            {
                this.myFans = myFans;
            }
            public void setCompany(Company myCompany)
            {
                this.myCompany = myCompany;
            }
            public void meeting()
            {
                Console.WriteLine(myFans.getName() + "与明星" + myStar.getName() + "见面了。");
            }
            public void business()
            {
                Console.WriteLine(myCompany.getName() + "与明星" + myStar.getName() + "洽淡业务。");
            }
        }
    View Code

    测试

                {
                    Console.WriteLine("--------------------------迪米特法则--------------------------------");
                    //明星 ----- 经纪人 ------ 粉丝、媒体;  明星不直接和粉丝、媒体打交道,都是通过经纪人来打交道
                    Agent agent = new Agent();
                    agent.setStar(new Star("吕饺子"));
                    agent.setFans(new Fans("粉丝李马茹"));
                    agent.setCompany(new Company("中国传媒有限公司"));
                    agent.meeting();
                    agent.business();
                }

    运行结果

    三. 组合聚合原则

    1. 定义

      也叫合成复用原则,指的是软件在复用的时候,优先使用组合和聚合的关系来实现,其次才是继承关系。

    PS:如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。

    扩展:适配器模式中的类适配模式,是通过继承的方式实现的;对象适配模式,是通过组合的方式实现的。

    2. 优点

    继承复用存在以下缺点:

     (1). 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。

     (2). 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。

     (3). 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。

    组合聚合复用存在以下优点:

     (1). 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。

     (2). 新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。

     (3). 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

    3. 实现方法和案例

    (1). 实现方法

     组合聚合原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。

    (2). 案例

    相关类

        /// <summary>
        /// 封装最基本的四则运算方法
        /// </summary>
        public class MyBaseHelp
        {
    
            public int Add(int a,int b)
            {
                return a + b;
            }
    
            public int Multiply(int a, int b)
            {
                return a * b;
            }
    
        }
     public class MyChildHelp1
        {
            //复用原则
            public MyBaseHelp _baseHelp;
            public MyChildHelp1()
            {
                _baseHelp = new MyBaseHelp();
            }
    
            /// <summary>
            /// 特殊计算
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public int SpecialCalculate(int a, int b)
            {
                return _baseHelp.Add(a, b) + _baseHelp.Multiply(a, b);
            }
    
        }

    测试

              Console.WriteLine("--------------------------组合聚合原则--------------------------------");
                    MyChildHelp1 help1 = new MyChildHelp1();
                    Console.WriteLine($"特殊运算结果为:{help1.SpecialCalculate(10, 4)}");  

    运行结果

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    【转】VS2010中 C++创建DLL图解
    [转]error: 'retainCount' is unavailable: not available in automatic reference counting mode
    [转]关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法
    【转】 Tomcat v7.0 Server at localhost was unable to start within 45
    【转】Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If
    【转】SVN管理多个项目版本库
    【转】eclipse安装SVN插件的两种方法
    【转】MYSQL启用日志,和查看日志
    【转】Repository has not been enabled to accept revision propchanges
    【转】SVN库的迁移
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/13539035.html
Copyright © 2011-2022 走看看