精华内容
下载资源
问答
  • 设计模式六大原则(6):开闭原则

    万次阅读 多人点赞 2012-02-27 08:48:41
    定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,... 开闭原则是面向对象设计中

    定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

    问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。

    解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

             开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修改关闭,并没有明确的告诉我们。以前,如果有人告诉我“你进行设计的时候一定要遵守开闭原则”,我会觉的他什么都没说,但貌似又什么都说了。因为开闭原则真的太虚了。

             在仔细思考以及仔细阅读很多设计模式的文章后,终于对开闭原则有了一点认识。其实,我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。也就是说,只要我们对前面5项原则遵守的好了,设计出的软件自然是符合开闭原则的,这个开闭原则更像是前面五项原则遵守程度的“平均得分”,前面5项原则遵守的好,平均分自然就高,说明软件设计开闭原则遵守的好;如果前面5项原则遵守的不好,则说明开闭原则遵守的不好。

             其实笔者认为,开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

             说到这里,再回想一下前面说的5项原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。

             最后说明一下如何去遵守这六个原则。对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说,我们一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要我们刻板的遵守他们,而需要根据实际情况灵活运用。对他们的遵守程度只要在一个合理的范围内,就算是良好的设计。我们用一幅图来说明一下。

     

     

            图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。

     

            在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。

             到这里,设计模式的六大原则就写完了。主要参考书籍有《设计模式》《设计模式之禅》《大话设计模式》以及网上一些零散的文章,但主要内容主要还是我本人对这六个原则的感悟。写出来的目的一方面是对这六项原则系统地整理一下,一方面也与广大的网友分享,因为设计模式对编程人员来说,的确非常重要。正如有句话叫做一千个读者眼中有一千个哈姆雷特,如果大家对这六项原则的理解跟我有所不同,欢迎留言,大家共同探讨。

     下面是前面5项设计原则的链接

    1.  单一职责原则(Single Responsibility Principle)

    2.  里氏替换原则(Liskov Substitution Principle)

    3.  依赖倒置原则(Dependence Inversion Principle)

    4.  接口隔离原则(Interface Segregation Principle)

    5.  迪米特法则(Law Of Demeter)

    同时为了方便想收藏的朋友,下面给出word版本的下载。

    word版本下载链接:设计模式六大原则

     

     

    展开全文
  • public abstract class Publisher { private List<IReader> _readers = new List<IReader>(); public string Name { get;... private const string LINE_BREAK = "----------------------------------...
  • 六大设计原则之开闭原则

    万次阅读 多人点赞 2016-08-28 10:32:38
    开闭原则的定义开闭原则是java世界里最基础的设计原则,它指导我们如何建立一个稳定,灵活的系统。开闭原则定义如下:Software entities like classes,modules and functions should be open for extension but ...

    这里写图片描述

    开闭原则的定义

    开闭原则是java世界里最基础的设计原则,它指导我们如何建立一个稳定,灵活的系统。开闭原则定义如下:

    Software entities like classes,modules and functions should be open for extension but closed for modifications.

    一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。

    什么是开闭原则

    开闭原则明确的告诉我们:软件实现应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化的。那什么是软件实体呢?软件实体包括以下几个部分:

    • 项目或软件产品中按照一定的逻辑规则划分的模块
    • 抽象和类
    • 方法
      一个软件产品只要在生命周期内,都会发生变化,即然变化是一个事实,我们就应该在设计时尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现“拥抱变化”。开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。

    我们举例说明什么是开闭原则,以书店销售书籍为例,其类图如下:

    这里写图片描述

    书籍接口:

    public interface IBook{
      public String getName();
      public String getPrice();
      public String getAuthor();
    }
    

    小说类书籍:

    public class NovelBook implements IBook{
       private String name;
       private int price;
       private String author;
    
       public NovelBook(String name,int price,String author){
         this.name = name;
         this.price = price;
         this.author = author;
       }
    
       public String getAutor(){
         return this.author;
       }
    
       public String getName(){
         return this.name;
       }  
    
       public int getPrice(){
         return this.price;
       } 
    }
    

    Client类:

    public class Client{
       public static void main(Strings[] args){
         IBook novel = new NovelBook("笑傲江湖",100,"金庸");
         System.out.println("书籍名字:"+novel.getName()+"书籍作者:"+novel.getAuthor()+"书籍价格:"+novel.getPrice());
       }
    
    }
    

    项目投产生,书籍正常销售,但是我们经常因为各种原因,要打折来销售书籍,这是一个变化,我们要如何应对这样一个需求变化呢?

    我们有下面三种方法可以解决此问题:

    • 修改接口
      在IBook接口中,增加一个方法getOffPrice(),专门用于进行打折处理,所有的实现类实现此方法。但是这样的一个修改方式,实现类NovelBook要修改,同时IBook接口应该是稳定且可靠,不应该经常发生改变,否则接口作为契约的作用就失去了。因此,此方案否定。

    • 修改实现类
      修改NovelBook类的方法,直接在getPrice()方法中实现打折处理。此方法是有问题的,例如我们如果getPrice()方法中只需要读取书籍的打折前的价格呢?这不是有问题吗?当然我们也可以再增加getOffPrice()方法,这也是可以实现其需求,但是这就有二个读取价格的方法,因此,该方案也不是一个最优方案。

    • 通过扩展实现变化
      我们可以增加一个子类OffNovelBook,覆写getPrice方法。此方法修改少,对现有的代码没有影响,风险少,是个好办法。

    下面是修改后的类图:

    这里写图片描述

    打折类:

    public class OffNovelBook implements NovelBook{
    
       public OffNovelBook(String name,int price,String author){
          super(name,price,author);
       }
    
       //覆写价格方法,当价格大于40,就打8析,其他价格就打9析
       public int getPrice(){
         if(this.price > 40){
            return this.price * 0.8;
         }else{
            return this.price * 0.9;
         }     
       } 
    }
    

    现在打折销售开发完成了,我们只是增加了一个OffNovelBook类,我们修改的代码都是高层次的模块,没有修改底层模块,代码改变量少,可以有效的防止风险的扩散。

    我们可以把变化归纳为二种类型:

    • 逻辑变化
      只变化了一个逻辑,而不涉及其他模块,比如一个算法是abc,现在需要修改为a+b+c,可以直接通过修改原有类中的方法的方式来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理

    • 子模块变化
      一人模块变化,会对其它的模块产生影响,特别是一个低层次的模块变化必然引起高层模块的变化,因此在通过扩展完成变化。

    为什么使用开闭原则

    第一:开闭原则非常有名,只要是面向对象编程,在开发时都会强调开闭原则

    第二:开闭原则是最基础的设计原则,其它的五个设计原则都是开闭原则的具体形态,也就是说其它的五个设计原则是指导设计的工具和方法,而开闭原则才是其精神领袖。依照java语言的称谓,开闭原则是抽象类,而其它的五个原则是具体的实现类。

    第三:开闭原则可以提高复用性
    在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来,不是在一个类中独立实现一个业务逻辑。只有这样的代码才可以复用,粒度越小,被复用的可能性越大。那为什么要复用呢?减少代码的重复,避免相同的逻辑分散在多个角落,减少维护人员的工作量。那怎么才能提高复用率呢?缩小逻辑粒度,直到一个逻辑不可以分为止。

    第四:开闭原则可以提高维护性
    一款软件量产后,维护人员的工作不仅仅对数据进行维护,还可能要对程序进行扩展,维护人员最乐意的事是扩展一个类,而不是修改一个类。让维护人员读懂原有代码,再进行修改,是一件非常痛苦的事情,不要让他在原有的代码海洋中游荡后再修改,那是对维护人员的折磨和摧残。

    第五:面向对象开发的要求
    万物皆对象,我们要把所有的事物抽象成对象,然后针对对象进行操作,但是万物皆发展变化,有变化就要有策略去应对,怎么快速应对呢?这就需要在设计之初考虑到所有可能变化的因素,然后留下接口,等待“可能”转变为“现实”。

    如何使用开闭原则

    第一:抽象约束
    抽象是对一组事物的通用描述,没有具体的实现,也就表示它可以有非常多的可能性,可以跟随需求的变化而变化。因此,通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:

    • 通过接口或抽象类约束扩散,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。
    • 参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求
    • 抽象层尽量保持稳定,一旦确定就不要修改

    第二:元数据(metadata)控件模块行为
    编程是一个很苦很累的活,那怎么才能减轻压力呢?答案是尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗的说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

    第三:制定项目章程
    在一个团队中,建立项目章程是非常重要的,因为章程是所有人员都必须遵守的约定,对项目来说,约定优于配置。这比通过接口或抽象类进行约束效率更高,而扩展性一点也没有减少。

    第四:封装变化
    对变化封装包含两层含义:
    (1)将相同的变化封装到一个接口或抽象类中
    (2)将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。
    封装变化,也就是受保护的变化,找出预计有变化或不稳定的点,我们为这些变化点创建稳定的接口。

    参考:

    设计模式之禅 秦小波著 机械工业出版社

    展开全文
  • 面向对象设计原则之2-开放闭合原则

    万次阅读 2018-07-14 18:25:45
    开放闭合原则(Open-Closed Principle or OCP) 开放闭合原则又叫开闭原则,即软件实体应当对扩展开放,对修改封闭。 OCP:Software entities should be open for extension,but closed for madification. 开闭...

    开放闭合原则(Open-Closed Principle or OCP)

    该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/341 访问。

    开放闭合原则又叫开闭原则,即软件实体应当对扩展开放,对修改封闭。

    OCP:Software entities should be open for extension,but closed for madification.

    开闭原则就是指软件实体应当尽量保证在不修改原有代码的情况下,对软件进行扩展。开闭原则是面向对象设计的基石。

    示例:

    public interface IMobilePhone {
    
        decimal Price { get; set; }
        string Model { get; set; }
        Color Color { get; set; }
    
    }
    public enum Color {
        Black,
        White
    }

    首先用IMobilePhone接口建立手机契约,并向外暴露3个属性,Price属性为手机价格,Model属性为手机型号,Color属性为手机外观颜色,接下来我们用此接口实现一个ApplePhoneX的类。

    注:手机接口IMobilePhone最好不要命名为IPhone,ApplePhoneX类不要命名为IPhoneX,因为这容易引起误解。

    public class ApplePhoneX : IMobilePhone {
    
        public virtual double Price {
            get => 8799;
            set => Price = value;
        }
    
        public virtual string Model {
            get => "IPhone X";
            set => Model = value;
        }
    
        public virtual Color Color {
            get => Color.Black;
            set => Color = value;
        }
    
    }

    以下是一个调用方可能的代码:

    IMobilePhone mobilePhone = new ApplePhoneX();
    var price = mobilePhone.Price;

    现在需求发生了变化,因为IPhone9上市在即,库克决定为IPhoneX打折促销,黑色的IPhoneX降价为6500.00元,白色的IPhoneX降价为6450.00元, 容易想到的一个做法是,修改IMobilePhone接口,增加DiscountPrice属性,可能如下所示:

    public interface IMobilePhone {
    
        double Price { get; set; }
        string Model { get; set; }
        Color Color { get; set; }
        double DiscountPrice { get; set; }//增加
    
    }
    public class ApplePhoneX : IMobilePhone {
    
        public virtual double Price {
            get => 8799;
            set => Price = value;
        }
    
        public virtual string Model {
            get => "IPhone X";
            set => Model = value;
        }
    
        public virtual Color Color {
            get => Color.Black;
            set => Color = value;
        }
    
        public virtual double DiscountPrice {//增加
            get => Color == Color.Black ? 6500.00 : 6450.00;
            set => DiscountPrice = value;
        }
    
    }
    public class HuaweiPhone : IMobilePhone {
        //需要修改
    }
    public class SmartisanPhone : IMobilePhone {
        //需要修改
    }

    但是这次修改将会影响到所有实现IMobilePhone接口的类,比如HuaweiPhone类和SmartisanPhone类。接口作为一种契约,应当是一种稳定的存在,不允许轻易修改,否则将明显违反开闭原则。以下给出一个解决方案以供参考: 

    public class DiscountApplePhoneX : ApplePhoneX {
    
        public override double Price {
            get => Color == Color.Black ? 6500.00 : 6450.00;
            set => Price = value;
        }
    
    }
    IMobilePhone mobilePhone = new DiscountApplePhoneX();
    var price = mobilePhone.Price;

    通过增加一个继承自ApplePhoneX的DiscountApplePhoneX类并重写Price方法来解决这个新需求,原来的所有代码均不需要更改,只要在使用打折手机的地方修改其使用即可,符合开闭原则。

    该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/341 访问。

    展开全文
  • 1. 加法原则 ( 1 ) 加法原则 ( 不能叠加 的事件才能用 加法原则 | 适用于 分类选取 ) ( 2 ) 乘法法则 ( 相互独立 的 事件 才能用 乘法法则 | 适用于 分步选择 ) 2. 习题解析 ( 1 ) 习题 1 ( 加法原理 ) ( 2 ) 习题 2...



    1. 加法原则



    ( 1 ) 加法原则 ( 不能叠加 的事件才能用 加法原则 | 适用于 分类选取 )


    加法原则 :

    • 1.加法法则描述 : 事件 A A A m m m 种 产生方式 , 事件 B B B n n n 种 产生方式 , 则 " 事件 A A A B B B " 有 m + n m + n m+n 种产生方式 ;
    • 1.加法法则推广 :事件 A 1 , A 2 , . . . , A n A_{1} , A_{2} , ... , A_{n} A1,A2,...,An 分别有 p 1 , p 2 , . . . , p n p_{1} , p_{2} , ... , p_{n} p1,p2,...,pn 种 产生方式 , 若 其中 任何 两个 事件 产生的方式 都 不重叠 , 则 " 事件 A 1 A_{1} A1 A 2 A_{2} A2 或 … 或 A n A_{n} An " 产生的方式 是 p 1 + p 2 + . . . + p n p_{1} + p_{2} + ... + p_{n} p1+p2+...+pn ;
    • 2.注意点 : 这里的 事件 A 1 , A 2 , . . . , A n A_{1} , A_{2} , ... , A_{n} A1,A2,...,An 必须是 不能重叠的 , 即 只有 一件 事件 发生 , 如果有多个 事件 同时发生 , 就必须 使用 乘法原则 ;
    • 3.适用问题 : 分类选取 ;



    ( 2 ) 乘法法则 ( 相互独立 的 事件 才能用 乘法法则 | 适用于 分步选择 )


    乘法原则 :

    • 1.乘法法则描述 : 事件 A 有 m 种 产生方式 , 事件 B 有 n 种 产生方式 , 则 " 事件 A 与 B " 有 mn 种产生方式 ;
    • 1.乘法法则推广 :事件 A 1 , A 2 , . . . , A n A_{1} , A_{2} , ... , A_{n} A1,A2,...,An 分别有 p 1 , p 2 , . . . , p n p_{1} , p_{2} , ... , p_{n} p1,p2,...,pn 种 产生方式 , 若 其中 任何 两个 事件 产生的方式 都 相互独立 , 则 " 事件 A 1 A_{1} A1 A 2 A_{2} A2 或 … 或 A n A_{n} An " 产生的方式 是 p 1 p 2 . . . p n p_{1} p_{2} ... p_{n} p1p2...pn ;
    • 2.注意点 : 这里的 事件 A 1 , A 2 , . . . , A n A_{1} , A_{2} , ... , A_{n} A1,A2,...,An 必须是 相互独立 的 ;
    • 3.适用问题 : 分步选取 ;



    2. 习题解析



    ( 1 ) 习题 1 ( 加法原理 )


    题目 :

    汽车市场 有 卡车 15 辆 , 面包车 8 辆 , 轿车 20 辆 ;
    从市场中只购买一辆车 , 有多少种购买方式 ?


    解答 :

    ① 这里用到了 加法原则 , 如果只能 买 一辆车的话 , 三种车 只能买一种 , 三个事件 是不能重叠的 ;

    ② 买卡车 有 15 种方式 , 买面包车 有 8 种方式 , 买轿车 有 20 种 , 三种方式只能选择一种 , 三者不能重叠 ( 同时存在 ) , 因此使用加法原则 进行计算 ;

    ③ 结果是 : 15 + 8 + 20 = 43 ;




    ( 2 ) 习题 2 ( 加法原则 乘法原则 综合运用 )


    A , B , C A , B , C A,B,C 是 3 个城市 ,
    A A A B B B 有 3 条路 , B B B C C C 有 2 条路 , A A A C C C 4 4 4 条路 ,
    问 从 A A A C C C 有多少种不同的方式 ?


    解 :

    加法原则 :
    ① 直接从 A A A C C C 与 ② 从 A A A 先到 B B B 再到 C C C 是 不能重叠的 , 方案 ① 与 方案 ② 需要 用家法原则 ,

    乘法原则 :
    方案 ② 内部需要使用 乘法原则 即 A A A B B B 有 3 种 选择 , B B B C C C 有 2 种选择 , 这两个选择是相互独立的 , 需要分步 选择 , 3 ∗ 2 = 6 3 * 2 = 6 32=6 ;

    最终 N = 3 × 2 + 4 = 10 N = 3 \times 2 + 4 = 10 N=3×2+4=10 ;




    ( 3 ) 习题 3 ( 乘法原则 )


    题目 :

    1000 1000 1000 9999 9999 9999 的 整数 中 :

    ① 含有5的数有多少个 ;
    ② 含有多少个 百位 和 十位数 均为 奇数 的 偶数 ;
    ③ 各位数 都不相同 的 奇数 有多少个;


    解答 :

    ( 1 ) 含有 5 的数 的个数 :

    ① 设 数字 集合 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \} {0,1,2,3,4,5,6,7,8,9}

    ② 直接求 含有 5 5 5 的数 , 比较麻烦 : 这里可以分成 1 1 1 位 含有 5 5 5 的数 , 此时又分成 个位 十位 百位 千位 四种情况 , 2 2 2 位 或 3 3 3 位 含有 5 5 5 更加复杂 ;

    ③ 这里 可以 转换一下思路 , 求 不含 5 的个数 :

    • 1> 千位 : 千位数 不能 取 0 0 0 5 5 5 , 只能取值 8 8 8 种情况 ;
    • 2> 百位 : 百位数 不能 取 5 5 5 , 9 9 9 种 取值情况 ;
    • 3> 十位 : 百位数 不能 取 5 5 5 , 9 9 9 种 取值情况 ;
    • 4> 个位 : 百位数 不能 取 5 5 5 , 9 9 9 种 取值情况 ;

    根据乘法原则 : 不含 5 5 5 的个数位为 8 × 9 × 9 × 9 = 5832 8 \times 9\times 9\times 9 = 5832 8×9×9×9=5832
    含有 5 的个数为 : 9000 − 5832 = 3168 9000 - 5832 = 3168 90005832=3168 ;



    ( 2 ) 百位 和 十位数 均为 奇数 的 偶数 :

    分析 四位 数 取值方案数 :

    • 1> 个位数取值方案数 : 考虑偶数的情况 : 如果为 偶数 , 那么 个位数 只能取值 { 0 , 2 , 4 , 6 , 8 } \{0, 2, 4 , 6, 8\} {0,2,4,6,8} 5 5 5 种情况 ;
    • 2> 十位数 和 百位数 取值 方案数 : 十位数 百位数 都是 奇数 , 那么 其 取值 { 1 , 3 , 5 , 7 , 9 } \{1 , 3 , 5 , 7 , 9 \} {1,3,5,7,9} , 也是 5 5 5 种方案 ;
    • 3> 千位数 取值 方案数 : { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{1 , 2, 3, 4, 5, 6, 7, 8, 9\} {1,2,3,4,5,6,7,8,9} , 有 9 9 9 种方案 ;

    根据 乘法 原则 : 百位 和 十位 均为 奇数 的 偶数 有 9 × 5 × 5 × 5 = 1125 9 \times 5 \times 5 \times 5 = 1125 9×5×5×5=1125 个 ;



    ( 3 ) 各位数 都不相同 的 奇数 个数 :

    逐位分析 :

    • 1> 分析 个位数 取值 : 个位数 如果不做限制的话 , 有 10 10 10 种方案数 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \} {0,1,2,3,4,5,6,7,8,9} , 要求 是 奇数 , 因此 个位数 只有 5 5 5 中方案 , 只能从 { 1 , 3 , 5 , 7 , 9 } \{1,3,5,7,9\} {1,3,5,7,9} 中取值 ;
    • 2> 分析 千位 的取值 : 千位数 不做限制的话 有 9 9 9 种方案 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{1, 2, 3, 4, 5, 6, 7, 8,9\} {1,2,3,4,5,6,7,8,9} , 如果要求 与 个位数不同 , 那么有 8 8 8 种方案 ;
    • 3> 分析 百位 数取值 : 百位数 如果不做限制的话 , 有 10 10 10 种方案数 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \} {0,1,2,3,4,5,6,7,8,9} , 千位 与 个位 各自 取了 一位数 , 那么只能下 8 8 8 种 方案数 ;
    • 4> 分析 十位 数取值 : 十位数 如果不做限制的话 , 有 10 10 10 种方案数 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \} {0,1,2,3,4,5,6,7,8,9} , 千位 , 个位 与 百位 各自 取了 一位数 , 那么只能下 7 7 7 种 方案数 ;

    根据乘法原则 : 1000 1000 1000 9999 9999 9999 的整数中 , 各个位数 都 不相同的 奇数 有 5 × 8 × 7 × 7 = 2240 5 \times 8 \times 7 \times 7 = 2240 5×8×7×7=2240 ;


    每一位分析的先后顺序很有讲究 , 一般先分析 条件限制比较苛刻的 选择 , 在分析 比较宽松的选择 ;


    关于一一对应 的说明 :
    如果 性质 A A A 的 计数 比较困难 , 性质 B B B 的计数比较容易 , 性质 A A A 和 性质 B B B 存在一一对应 , 那么对性质 A A A 的计数 , 可以转化为 对 性质 B B B 的计数 ;
    这里用到了 一一对应 , 如 上述 , 计数 含有 5 5 5 的整数个数 , 如果正面计数比较困难 , 可以反过来 计算 不含有 5 5 5 的整数个数 , 这样就比较好计数了 , 1000 1000 1000 9999 9999 9999 一共有 9000 9000 9000 个数 , 9000 − 不 含 5 的 整 数 个 数 9000 - 不含5的整数个数 90005 与 含有 5 5 5 的整数个数 是一一对应的 ;


    常用的一一对应 :
    ① 选取问题
    ② 不定方程非负整数解问题
    ③ 非降路径问题
    ④ 正整数拆分问题
    ⑤ 放球问题


    展开全文
  • Solid设计原则

    万次阅读 2020-10-25 23:56:15
    开闭原则(总纲,其他原则是其实现) 软件实体应当对扩展开放,对修改关闭 即当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求 1 里氏替换原则 子类...
  • ocp原则

    2011-10-17 02:08:05
    ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则ocp原则
  • 设计原则:开闭原则

    千次阅读 2021-03-01 23:49:04
    学了那么多设计模式,你知道开闭原则吗?
  • 六大设计原则之里氏替换原则

    万次阅读 2016-08-28 11:27:48
    里氏替换原则定义里氏替换原则(Liskov Substitution Principle,LSP): 第一种定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2,程序P的行为没有发生变化...
  • 当然,在设计模式中我们不只有各种模式,还有许多设计的原则,虽然他们不是代码架构的模板,但是这些原则却时刻提醒我们提高代码质量和防止未来麻烦。这次我就将单一职责原则、开放-封闭原则以及依赖倒转原则进行...
  • 【Java设计模式】软件设计七大原则

    万次阅读 多人点赞 2019-08-31 13:44:31
    文章目录软件设计原则的分类开闭原则依赖倒置原则单一职责原则接口隔离原则迪米特法则(最少知道原则)里氏替换原则合成/复用原则(组合/复用原则) 软件设计原则的分类 开闭原则 依赖倒置原则 单一职责原则 接口...
  • 面向对象设计原则之1-单一职责原则

    万次阅读 2018-07-14 16:04:36
    单一职责原则(Single Responsibility Principle or SRP) 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。 SRP:Every object should have a single responsibility,and that responsibility ...
  • 信息专家原则(Information ExpertPrinciple) (1)问题 给对象分配职责的通用原则是什么? (2)方案 将职责分配给拥有履行一个职责所必需信息的类,即信息专家。 (3)分析 信息专家原则是面向对象设计的最...
  • 面向对象设计原则之4-依赖倒置原则

    万次阅读 2018-07-15 12:27:05
    依赖倒置原则(Dependence Inversion Principle DIP ) 高层模块不应该依赖低层模块,他们都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。 简单的定义为:面向接口(抽象)编程,不要面向实现编程...
  • 面向对象设计原则之5-接口隔离原则

    万次阅读 2018-07-15 18:40:18
    接口隔离原则(Interface Segregation Principle or ISP) 客户端不应该依赖它不需要的接口。 ISP:Clients should not be forced to depend upon interfaces that they don’t use. 一个类对另外一个类的依赖性...
  • 设计原则

    千次阅读 2019-07-09 17:12:53
    ◆开闭原则 ◆依赖倒置原则 ◆单一职责原则 ◆接口隔离原则 ◆迪米特法则(最少知道原则) ◆里氏替换原则 ◆合成/复用原则(组合/复用原则
  • MySQL最左匹配原则,道儿上兄弟都得知道的原则

    千次阅读 多人点赞 2020-09-11 19:31:00
    目录一、最左匹配原则的原理二、违背最左原则导致索引失效的情况三、查询优化器偷偷干了哪些事儿四、需要你mark的知识点1、如何通过有序索引排序,避免冗余执行order by2、like 语句的索引问题3、不要在列上进行运算...
  • 正态分布中“sigma原则”,“2sigma原则”,“3sigma原则”正态分布3sigma原则正态分布中的参数含义 正态分布3sigma原则 正态分布中“sigma原则”、“2sigma原则”、“3sigma原则”分别是: sigma原则:数值分布在...
  • 六大设计原则-迪米特原则

    千次阅读 2020-03-23 17:27:07
    迪米特原则 什么是迪米特原则? 一个对象应该对其他对象保持最少的了解。 为什么要使用迪米特原则? 面向对象语言是万物皆对象,类与类之间交互越频繁,类与类之间的关系也就越密切,这就是耦合,耦合度越高...
  • 六大设计原则之依赖倒置原则

    万次阅读 2016-08-23 11:42:52
    依赖倒置原则定义依赖倒置原则(Dependence Inversion Principle ,DIP)定义如下:High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not ...
  • 架构设计五大原则 SOLID五大设计原则

    千次阅读 多人点赞 2021-05-18 17:22:50
    SRP:单一职责原则 容易误认为是指:一个软件模块都应该只做一件事,实际上并不准确。单一职责原则准确描述应该是:一个软件模块都应该只对一类行为负责。 如果多个特性不同的项目同时依赖同一个底层接口,只要有...
  • 什么是最少知识原则? 最少知识原则(LKP)说的是一个软件实体应当尽可能少地与其他实体发生相互作用。这里的软件实体是一个广义的概念,不仅包括对象,还包括系统、类、模块、函数、变量等。本节我们主要针对对象来...
  • 设计模式6大原则.doc

    千次下载 热门讨论 2012-02-27 09:05:05
    对设计模式六大原则的一点总结,欢迎免费下载。
  • 六大原则之开闭原则

    千次阅读 2021-02-02 10:23:59
    1. 开闭原则的介绍 开闭原则(Open Closed Principle)是编程中最基础、最重要设计原则 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。 当...
  • 英语“就近原则”和“就远原则

    万次阅读 2019-09-03 06:37:18
    什么是“就近原则”?什么是“就远原则”?是根据单词位置的“近”或“远”来判断的吗?在回答之前先做一道例子。 例1.What he does or what he says __ nothing to do with me. 他的行为或言谈都与我无关。 在这个...
  • 软件设计原则——SOLID原则

    千次阅读 2018-10-15 16:00:21
    文章目录SOLID原则单一责任原则开放/封闭原则里民代换原则常见代码问题错误示例代码辅助工具接口分离原则依赖反转原则 SOLID原则 单一责任原则(SRP) 开放/封闭原则(OCP) 里氏代换原则(LSP) 接口分离原则(ISP) ...
  • PDCA 原则与Smart原则

    千次阅读 热门讨论 2018-02-13 13:39:05
    今天学习了PDCA原则与smart原则,做好时间管理很重要,下面我来说一说我的理解 PDCA全面质量管理的思想基础和方法依据 P(plan)计划:根据已知的信息,设计具体的方法、方案 D(do)执行:在根据设计的方法和方案...
  • 六大设计原则-里氏替换原则

    千次阅读 2020-03-22 23:51:18
    里氏替换原则 什么是里氏替换原则? 里氏替换原则的定义:任何使用基类的地方,都可以透明的使用其子类。从定义中可以看出,它和继承差不多,我们也可以这样理解,里氏替换原则=继承+透明,也就是继承的加强版,取...
  • 什么是单一职责原则(SRP)? 单一职责原则(SRP)的职责被定义为“引起变化的原因”。如果我们有两个动机去改写一个方法,那么这个方法就具有两个职责。每个职责都是变化的一个轴线,如果一个方法承担了过多的职责...
  • 六大设计原则-开闭原则

    千次阅读 2020-03-27 21:21:25
    什么是开闭原则? 开闭原则就十个字:对扩展开放,对修改关闭。 什么是修改?什么是扩展? 修改:对现有的代码进行修改(修改BUG除外); 扩展:增加代码。 为什么有开闭原则? 面向对象语言是一种静态语言,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,286,301
精华内容 514,520
关键字:

原则