精华内容
下载资源
问答
  • java面向对象六大原则

    2018-09-28 14:46:02
    面向对象特点:  1:将复杂的事情简单化。  2:面向对象将以前的过程中的执行者,变成了指挥者。  3:面向对象这种思想是符合现在人们思考习惯的一种思想。 什么是面向对象呢?  面向对象是一种编程思想,...

    面向对象特点:

            1:将复杂的事情简单化。

            2:面向对象将以前的过程中的执行者,变成了指挥者。

            3:面向对象这种思想是符合现在人们思考习惯的一种思想。

    什么是面向对象呢?

            面向对象是一种编程思想,这种编程思想凸显对象在编程过程中的重要作用。

            简单的说就是让对象成为类与类之间的“通信”的桥梁,通过对象使类之间形成有机的整体。

            Java语言中的对象是对现实世界中对象的模拟,现实中的对象存在于现实生活中,Java语言中的对象存在于计算机内存中,Java语言中的对象又称为实例。

            Java中将现实对象中的信息静态特征称为属性(也叫全局变量),将现实对象中的功能动态特征称为方法。

            过程和对象在我们的程序中是如何体现的呢?过程其实就是函数;对象是将函数等一些内容进行了封装。

    面向对象与面向过程的区别

            面向对象是从宏观方面思考问题,而面向过程可以说是从细节处思考问题。

            面向对象编程语言以对象为中心,以消息为驱动,即程序=对象+消息;而面向过程编程语言则以过程为中心,以算法为驱动,即程序=算法+数据

            在面向对象中,也存在面向过程。

     

    面向对象6大原则

    1、单一职责原则

    定义:

            一个类只负责一项职责。

    优点

            降低类的复杂度,一个类只负责一个职责,其逻辑一定会比一个类负责多项职责要简单,同时也易于维护

            提高类的可读性,提高系统的可维护性

            低变更所带来的风险;系统的变更是必然的,如果单一职责原则遵守的好,那么当修改一个功能时可以显著降低对其他功能的影响

      虽说我们要遵守单一职责原则,但是也不是说死板的对每一个细节都严格遵守,也要视情况而定:如果一个类的逻辑非常简单且可以保证变化极小,此时可以在代码级别上违反单一职责原则;另外当一个类中方法很少时,也可以在方法的级别上违反这一原则。(这里我这么理解单一职责原则:分为两个层次,最高层次是类的层次,其次是方法层次上)但是如果一个类相对庞大,类中方法较多时,一定要遵守单一职责原则;宁愿在第一次扩展时花费精力完成重构,也要遵守这一原则,否则会给以后的扩展带来不可预估的灾难!

    2、里式替换原则

    定义

            如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换为o2时,程序P的行为没有发生变化;那么类型T2是类型T1的子类型

            所有引用基类的地方必须可以透明的使用其子类的对象

    通俗的讲就是:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也即在软件里面把父类都替换成他的子类,程序的行为没有发生任何变化。

      继承包含这样一层含义:父类中凡是已经实现好的方法(区别于抽象方法),实际上是在设定一系列的规则和契约,虽然它并不要求所有的子类都必须强制遵守这些规则,但是如果子类任意对这些非抽象方法进行重写,就会对整个继承体系造成破坏。里式替换原则主要就是想表达这一层含义。

      当然如果你非要重写父类的非抽象方法,这时应该采用这样的方式:原来的父类和子类都继承自一个更通用的基类,原有的继承关系去掉,转而采用依赖、聚合、组合等关系来替代。

      更通俗的说就是:子类可以扩展父类的功能,但是不能修改父类原有的功能;具体有以下4中含义:

            子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法

            子类可以增加自己特有的方法

            当子类的方法重载父类的方法时,方法的前置条件(形参)要比父类方法的输入方法更宽松

            当子类实现父类的抽象方法时,方法的后置条件(即方法返回值)要比父类更严格

    3、依赖倒转原则

    定义:

            抽象不应该依赖细节,细节应该依赖于抽象(说白了就是要针对接口编程,不要对实现编程);也即:

            高层模块不应该依赖于底层模块,二者都应该依赖于抽象;

            抽象不应该依赖于细节,细节应该依赖于抽象

            依赖倒转原则基于这样一个事实:相对于细节实现中的多变性,抽象的东西要稳定的多;以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。抽象一般指的是接口、抽象类,细节就是具体的实现类。使用抽象的目的是制定好规范和契约,而不要涉及具体的实现,把细节交给他们的实现类来完成。

      依赖倒转原则的核心就是面向接口编程,传递依赖关系有三种方式:接口传递、构造方法传递、setter传递(如果用过spring框架,那么对传递一定会很熟悉)。在实际的开发中我们主要通过以下几点来较好的遵守依赖倒转原则:

            底层模块尽量都要有抽象类或接口,或两者都有

            变量的声明类型尽量是抽象类或接口

            使用继承时要遵循里式替换原则

      遵循依赖倒转原则可以降低类之间的耦合性,提高系统稳定性,降低修改造成的风险。同时,采用依赖倒转原则给并行开发带来了极大的便利,参与开发的人越多、项目越庞大依赖倒转原则意义和好处就越明显。当前比较流行的TDD开发模式就是依赖倒置原则非常成功的应用。

    4、迪米特法则

    定义(也叫最少知道原则)

            如果两个类不必直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的方法,可以通过第三方来转发这个调用

    一个对象应该保持对其他对象最少的了解

      通俗的来讲,就是一个类对自己以来的类知道的越少越好;也就是说对于被依赖的类来说,无论逻辑多么复杂,都应当把逻辑封装在内部,对外除了提供public方法之外,不泄露其他任何信息。再通俗来说:迪米特法则就是‘只与直接的朋友通信’。那么什么是直接的朋友呢:每个对象都会与其他对象有耦合关系,只要两个对象间出现耦合关系,我们就说两个对象之间是朋友关系。而耦合的方式有很多,依赖、关联、聚合、组合都是耦合关系;其中,我们称出现成员变量、方法参数、方法返回值中的类为直接朋友,而出现在局部变量中的类则是间接朋友关系。也就是说陌生的类最好不要作为局部变量的形式出现在类的内部。

      迪米特法则的初衷是降低类之间的耦合,但是凡事都有一个度,虽然可以避免与非直接类之间的通信,但是要通信就必须通过一个中介来发生关系;而过分的使用迪米特法则,就会产生大量这样的中介和传递类,导致系统的复杂度增加。所以在使用迪米特法则时,要反复权衡,既要做到结构清晰又要高内聚低耦合。

    5、开放-封闭原则

    定义:

            一个软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭;即可以扩展但是不能修改

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

      开放-封闭原则是面向对象设计中最基础的原则,它指导我们如何建立稳定、灵活的系统。但是他也是这几个模式中定义最为模糊的一个,在初接触它时,总给你一种无处下手的感觉,因为它太虚了。但是当把其他原则还有23中设计模式通读了一遍之后,我发现可以这么理解它:开放-封闭原则是战略,而其他的几个原则以及设计模式就是具体的战术;如何实现开放-封闭原则呢?要想实现一个战略,就必须要制定合适的战术:即,通过较好的遵守其他几个原则以及通过合适的设计模式,最终实现一个软件很好的开发-封闭原则。

    6、接口隔离原则

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

      可以这么理解:如果接口过于臃肿,那么实现他的类不管用不用的到,都必须实现接口中所有的方法,这显然是不好的设计;这时候就需要遵循接口隔离原则对臃肿的接口进行拆分。他的原则就是:尽量建立单一的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不是试图去建立一个很庞大的接口共所有依赖他的类去调用。

      这里接口隔离原则与单一职责原则也有一定的区别,主要从以下方面来看:

    单一职责原则注重的是职责,而接口隔离注重的是对接口依赖的隔离;

    单一职责原则主要约束的是类,其次才是接口和方法,它主要针对的是程序中实现的细节;而接口隔离原则主要针对接口和抽象,针对程序框架的构建。

      但是在使用接口隔离原则时也一定要适度,一定要注意:

    接口尽量小,但是也要有限度。如果接口过小,会造成接口过多,而导致增加设计的复杂度。

    为依赖接口的类定制服务,只暴露给调用他的类所需要的方法,他不需要的方法则要隐藏起来。只有专注的为一个模块提供定制服务,才能建立最小的依赖关系。

    转载自:https://blog.csdn.net/niudasheng/article/details/80595217

    展开全文
  • java面向对象设计的六大原则
  • 面向对象六大原则 在此之前,有一点需要大家知道,熟悉这些原则并不是说你写出的程序就一定灵活、清晰,只是为你优秀的代码之路铺上了一层栅栏,在这些原则的指导下,你才能避免陷入一些常见的代码泥沼,从而让你写...

    面向对象六大原则

    在此之前,有一点需要大家知道,熟悉这些原则并不是说你写出的程序就一定灵活、清晰,只是为你优秀的代码之路铺上了一层栅栏,在这些原则的指导下,你才能避免陷入一些常见的代码泥沼,从而让你写出优秀的东西。

    单一职责原则

    展开全文
  • 3.依赖倒置原则面向接口编程 4.接口隔离原则: 客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 5.迪米特法则还有一个更简单的定义:只与直接的朋友通信。其中,我们称出现成员...
  • java面向对象程序设计的(七)基本原则

    1.开闭原则(Open Close Principle)

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

    开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改了,如果新需求来,我们增加一些类就完事了,原来的代码能不动则不动。这个原则有两个特性,一个是说“对于扩展是开放的”,另一个是说“对于更改是封闭的”。面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。这就是“开放-封闭原则”的精神所在

    比如,刚开始需求只是写加法程序,很快在client类中完成后,此时变化没有发生,需求让再添加一个减法功能,此时会发现增加功能需要修改原来这个类,这就违背了开放-封闭原则,于是你就应该考虑重构程序,增加一个抽象的运算类,通过一些面向对象的手段,如继承、动态等来隔离具体加法、减法与client耦合,需求依然可以满足,还能应对变化。此时需求要添加乘除法功能,就不需要再去更改client及加减法类,而是增加乘法和除法子类即可。

    绝对的修改关闭是不可能的,无论模块是多么的‘封闭‘,都会存在一些无法对之封闭的变化,既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。在我们最初编写代码时,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生同类的变化。

    我们希望的是在开发工作展开不久就知道可能发生的变化,查明可能发生的变化所等待的时候越长,要创建正确的抽象就越困难。开放-封闭原则是面向对象设计的核心所在,遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出现频繁变化的那些部分做出抽象,然而对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意,拒绝不成熟的抽象和抽象本身一样重要。开放-封闭原则,可以保证以前代码的正确性,因为没有修改以前代码,所以可以保证开发人员专注于将设计放在新扩展的代码上。

    简单的用一句经典的话来说:过去的事已成历史,是不可修改的,因为时光不可倒流,但现在或明天计划做什么,是可以自己决定(即扩展)的。

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

    定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

    定义2:子类型必须能够替换掉它们的父类型。

    描述:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化

    例子:在生物学分类上,企鹅是一种鸟,但在编程世界里,企鹅却不能继承鸟。在面向对象设计时,子类拥有父类所有非private的行为和属性,鸟会飞,但企鹅不会飞,所以企鹅不能继承鸟类。

    只有当子类可以替换掉父类,软件单位的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为,正是有里氏代换原则,使得继承复用成为了可能。正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展,不然还谈什么扩展开放,修改关闭呢

    里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

    1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

    2.子类中可以增加自己特有的方法。

    3.当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

    4.当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

    看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?

    后果就是:你写的代码出问题的几率将会大大增加。

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

    定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程

    依赖倒转其实就是谁也不要依靠谁,除了约定的接口,大家都可以灵活自如。依赖倒转可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了。如果设计的各个部件或类相互依赖,这样就是耦合度高,难以维护和扩展,这也就体现不出面向对象的好处了。

    依赖倒转原则,好比一个团队,有需求组,开发组,测试组,开发组和测试组都是面对同样的需求后,做自己相应的工作,而不应该是测试组按照开发组理解的需求去做测试用例,也就是说开发组和测试组都是直接面向需求组工作,大家的目的是一样的,保证产品按时上线,需求是不依赖于开发和测试的。

    依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

    依赖倒置原则的中心思想是面向接口编程,传递依赖关系有三种方式,以上的说的是是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。

    在实际编程中,我们一般需要做到如下3点:

    低层模块尽量都要有抽象类或接口,或者两者都有。

    变量的声明类型尽量是抽象类或接口。

    使用继承时遵循里氏替换原则。

    总之,依赖倒置原则就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

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

    接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

    说到这里,很多人会觉的接口隔离原则跟单一职责原则很相似,其实不然。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。

    采用接口隔离原则对接口进行约束时,要注意以下几点:

    1. 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。

    2. 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。

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

    运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。

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

    迪米特法则其根本思想,是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成影响,也就是说,信息的隐藏促进了软件的复用。

    自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

    迪米特法则又叫最少知道原则,最早是在1987年由美国Northeastern University的Ian Holland提出。通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

    一句话总结就是:一个对象应该对其他对象保持最少的了解。

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

    定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责,应该仅有一个引起它变化的原因

    说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。

    遵循单一职责原的优点有:

    1.可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;

    2.提高类的可读性,提高系统的可维护性;

    3.变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

    需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都需要遵循这一重要原则。

    7.组合/聚合复用原则

    就是说要尽量的使用合成和聚合,而不是继承关系达到复用的目的

    该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。

    其实这里最终要的地方就是区分“has-a”和“is-a”的区别。相对于合成和聚合,

    继承的缺点在于:父类的方法全部暴露给子类。父类如果发生变化,子类也得发生变化。聚合的复用的时候就对另外的类依赖的比较的少。。

    合成/聚合复用

    ① 优点:

    新对象存取成分对象的唯一方法是通过成分对象的接口;

    这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的;

    这种复用支持包装;

    这种复用所需的依赖较少;

    每一个新的类可以将焦点集中在一个任务上;

    这种复用可以在运行时动态进行,新对象可以使用合成/聚合关系将新的责任委派到合适的对象。

    ② 缺点:

    通过这种方式复用建造的系统会有较多的对象需要管理。

    继承复用

    ① 优点:

    新的实现较为容易,因为基类的大部分功能可以通过继承关系自动进入派生类;

    修改或扩展继承而来的实现较为容易。

    ② 缺点:

    继承复用破坏包装,因为继承将基类的实现细节暴露给派生类,这种复用也称为白箱复用;如果基类的实现发生改变,那么派生类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,不够灵活。

    展开全文
  • 面向对象六大原则

    万次阅读 多人点赞 2019-02-13 18:36:34
    一、面向对象六大原则  现在的编程的主流语言基本上都是面向对象的。我们知道,面向对象是一种编程思想,包括三大特性和六大原则,其中,三大特性指的是封装、继承和多态;六大原则指的是单一职责原则、开闭式...

    一、面向对象的六大原则

           现在的编程的主流语言基本上都是面向对象的。我们知道,面向对象是一种编程思想,包括三大特性和六大原则,其中,三大特性指的是封装、继承多态;六大原则指的是单一职责原则、开闭式原则、迪米特原则、里氏替换原则、依赖倒置原则以及接口隔离原则其中,单一职责原则是指一个类应该是一组相关性很高的函数和数据的封装,这是为了提高程序的内聚性,而其他五个原则是通过抽象来实现的,目的是为了降低程序的耦合性以及提高可扩展性。在应用的开发过程中,最难的不是完成应用的开发工作,而是在后续的升级、维护过程中让系统能够拥抱变化。拥抱变化也意味着在满足需求且不破坏系统稳定性的前提下保持高可扩展性、高内聚、低耦合,在经历了各个版本的变更之后依然能够保持清晰、灵活、稳定的系统架构。当然,这是一种比较理想的情况,由于各种各样的原因(开发水平差、工期短、产品奇葩需求等),我们的应用可能会变得难以维护,但是我们必须向更好的方向努力,那么遵循面向对象的六大原则就是我们走向灵活软件之路所迈出的第一步。本篇文章将以实现一个简单的图片加载框架为例,来说明面向对象六大原则的应用。

    二、图片加载框架需求分析

    需求描述

    1、需要根据Url将图片加载到对应的ImageView上;

    2、需要图片缓存功能;

    3、框架提供的API尽可能简单,方便使用;

    4、框架能够灵活的扩展,比如灵活的改变缓存功能、下载图片方法等;

    需求分析

    分析一下需求,我们至少需要使用以下技术:

    1、首先,我们需要根据Url下载图片,这里暂定使用UrlConnection;

    2、为了不阻塞UI线程,我们下载图片需要在子线程中执行,方便起见,我们直接使用线程池;

    3、在子线程中下载图片后,我们需要将图片显示到ImageView上,由于Android的特性,我们需要在UI线程中更新UI,所以这里需要使用Handler来切换线程到UI线程中显示图片;

    4、图片需要缓存功能,一般图片缓存需要有内存缓存和文件缓存,内存缓存就是将下载好的图片保存在内存中,下次使用时直接从内存中获取,这里采用Lru算法来控制图片缓存,文件缓存即将图片缓存到文件中,下次使用直接从文件中获取,相对来说,内存缓存会占用较多的内存,但是效率较高。

    三、源码实现

    我们首先只实现功能,而不管代码的好坏,后面我们再根据六大原则对代码进行优化,看看遵循六大原则究竟能够带来哪些好处。

    public class ImageLoader {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        private LruCache<String, Bitmap> mLruCache = new LruCache<>(maxMemory / 4); // 内存缓存
        ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // 下载图片使用的线程池
        private Handler mDealHandler = new Handler() { // 处理下载好图片的Handler
            @Override
            public void handleMessage(Message msg) {
                if (msg != null && msg.obj != null) {
                    ImageResponse imageResponse = (ImageResponse) msg.obj;
                    imageResponse.imageView.setImageBitmap(imageResponse.bitmap); // 将图片显示到ImageView上
                    mLruCache.put(imageResponse.imageUrl, imageResponse.bitmap); // 将图片保存到缓存中
                }
            }
        };
    
        /**
         * 加载图片
         * @param imageView
         * @param imageUrl
         */
        public void displayImage(final ImageView imageView, final String imageUrl) {
            if (imageView == null || TextUtils.isEmpty(imageUrl)) {
                return;
            }
    
            Bitmap cacheBitmap = mLruCache.get(imageUrl);
            if (cacheBitmap == null) { // 使用缓存失败
                mExecutorService.submit(new Runnable() { // 使用线程池下载图片
                    @Override
                    public void run() {
                        Bitmap bitmap = downLoadImage(imageUrl); // 下载图片
                        if (bitmap != null) {
                            ImageResponse imageResponse = new ImageResponse(); // 图片下载好后,将信息封装成Message发送给Handler处理
                            imageResponse.bitmap = bitmap;
                            imageResponse.imageUrl = imageUrl;
                            imageResponse.imageView = imageView;
                            Message message = Message.obtain();
                            message.obj = imageResponse;
                            mDealHandler.sendMessage(message);
                        }
                    }
                });
            } else {
                imageView.setImageBitmap(cacheBitmap);
            }
        }
    
        // 下载图片
        public Bitmap downLoadImage(final String imageUrl) {
            Bitmap bitmap = null;
            try {
                URL url = new URL(imageUrl);
                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                bitmap = BitmapFactory.decodeStream(connection.getInputStream());
                connection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return bitmap;
        }
        
        public static class ImageResponse {
            public Bitmap bitmap;
            public ImageView imageView;
            public String imageUrl;
        }
    }

    使用方法:

        ImageLoader mImageLoader = new ImageLoader();
        mImageLoader.displayImage(imageView, imageUrl);

    在上面的代码中,我们不管三七二十一,将所有的功能都堆积到了ImageLoader这个类中,ImageLoader不仅承担了提供Api接口的功能,同时还承担了具体实现细节的功能,比如缓存功能、下载图片功能、显示图片功能等等,这样虽然也能实现图片加载的效果,但是确会让我们的代码变得臃肿复杂并且难以维护,不说别人看不懂,可能过个几天后连自己都看不懂了,所以,我们自然而然的要想到,我们需要根据功能对类进行细分,将某些相关性很强的功能分到独立的类中去处理,比如,图片的缓存我们可以划分为一个类,图片的下载可以作为另外一个类,通过类的划分,我们可以让代码变得清晰,这也就是面向对象六大原则中的第一个原则----单一职责原则

    优化代码第一步----单一职责原则----高内聚

    单一职责原则的定义是:就一个类而言,应该只有一个引起它变化的原因。简单来说,一个类应该是一组相关性很高的函数和数据的封装。因为单一职责的划分界限并不是那么清晰,每个人的理解不一样,这就导致了不同的人划分的类承担的职责也不一样,就图片加载的例子来说,可能有的人就认为整个图片加载是一组相关性很高的功能,于是将其放入在一个类中处理。一般来说,我们首先需要具备单一职责原则的思想,如果发现一个类承担了太多的功能,这个时候就要考虑将某些功能划分到其他类中去处理,具体的划分细节要平开发者的个人经验。

    下面,我们利用单一职责原则的思想对ImageLoader进行改造,根据功能来说,下载图片和图片缓存应该属于单独的功能,我们可以分别用两个类来实现,然后ImageLoader调用这两个类即可:

    public class ImageLoader {
        ImageCache mImageCache = new ImageCache();
        RequestImage mRequestImage = new RequestImage();
        
        private Handler mDealHandler = new Handler() { // 处理下载好图片的Handler
            @Override
            public void handleMessage(Message msg) {
                if (msg != null && msg.obj != null) {
                    ImageResponse imageResponse = (ImageResponse) msg.obj;
                    imageResponse.imageView.setImageBitmap(imageResponse.bitmap); // 将图片显示到ImageView上
                    mImageCache.put(imageResponse.imageUrl, imageResponse.bitmap); // 将图片保存到缓存中
                }
            }
        };
    
        /**
         * 加载图片
         * @param imageView
         * @param imageUrl
         */
        public void displayImage(final ImageView imageView, final String imageUrl) {
            if (imageView == null || TextUtils.isEmpty(imageUrl)) {
                return;
            }
    
            Bitmap cacheBitmap = mImageCache.get(imageUrl);
            if (cacheBitmap == null) { // 使用缓存失败
                mRequestImage.requestImage(imageView, imageUrl, mDealHandler);
            } else {
                imageView.setImageBitmap(cacheBitmap);
            }
        }
        
        public static class ImageResponse {
            public Bitmap bitmap;
            public ImageView imageView;
            public String imageUrl;
        }
    }
    
    public class RequestImage {
        ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // 下载图片使用的线程池
    
        public void requestImage(final ImageView imageView, final String imageUrl, final Handler handler) {
            mExecutorService.submit(new Runnable() { // 使用线程池下载图片
                @Override
                public void run() {
                    Bitmap bitmap = downLoadImage(imageUrl); // 下载图片
                    if (bitmap != null) {
                        ImageLoader.ImageResponse imageResponse = new ImageLoader.ImageResponse(); // 图片下载好后,将信息封装成Message发送给Handler处理
                        imageResponse.bitmap = bitmap;
                        imageResponse.imageUrl = imageUrl;
                        imageResponse.imageView = imageView;
                        Message message = Message.obtain();
                        message.obj = imageResponse;
                        handler.sendMessage(message);
                    }
                }
            });
        }
    
        // 下载图片
        public Bitmap downLoadImage(final String imageUrl) {
            Bitmap bitmap = null;
            try {
                URL url = new URL(imageUrl);
                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                bitmap = BitmapFactory.decodeStream(connection.getInputStream());
                connection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return bitmap;
        }
    }
    
    public class ImageCache {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        private LruCache<String, Bitmap> mLruCache = new LruCache<>(maxMemory / 4); // 内存缓存
    
        public void put(String url, Bitmap bitmap) {
            if (!TextUtils.isEmpty(url) && bitmap != null) {
                mLruCache.put(url, bitmap);
            }
        }
    
        public Bitmap get(String url) {
            return mLruCache.get(url);
        }
    }

    可以看到,经过单一职责原则的优化,我们的ImageLoader变得简洁了许多,也更加易于维护,比如,我们想修改缓存相关功能,只需要查看ImageCache类即可。我们并没有对具体功能代码做修改,只是将相关性较高的功能单独提取了出来,封装成类。单一职责原则也就是我们经常说的高内聚。

    更高的可扩展性----开闭式原则

    经过单一职责原则的优化,我们的ImageLoader变得不再臃肿,但是,还远远没有达到要求,我们在需求中说过,ImageLoader需要支持内存缓存和文件缓存,现在我们只支持了内存缓存,可能你会说,在原来的基础上加上文件缓存不就可以了吗?我们先来看看,直接在ImageLoader中加入文件缓存后的代码会是什么样的:

        MemoryImageCache mMemoryImageCache = new MemoryImageCache();
        DiskImageCache mDiskImageCache = new DiskImageCache(App.getAppContext());
        private int mCacheType = 1;
        public final static int MEMORY_CACHE_TYPE = 1;
        public final static int DISK_CACHE_TYPE = 2;
    
        /**
         * 设置缓存类型
         * @param type
         */
        public void setCacheType(int type) {
            mCacheType = type;
        }
    

    首先,我们添加了一个变量mCacheType来保存缓存类型,并提供了一个setCacheType方法来设置缓存类型,然后在使用缓存时,我们需要根据保存的缓存类型来确定到底该使用哪个缓存:

        switch (mCacheType) {
    	        case MEMORY_CACHE_TYPE:
    	            mMemoryImageCache.put(imageResponse.imageUrl, imageResponse.bitmap); // 将图片保存到内存缓存中
    	            break;
    	        case DISK_CACHE_TYPE:
    	            mDiskImageCache.put(imageResponse.imageUrl, imageResponse.bitmap); // 将图片保存在磁盘缓存中
    	            break;
    	    }
    
        Bitmap cacheBitmap = null;
        switch (mCacheType) {
            case MEMORY_CACHE_TYPE:
                cacheBitmap = mMemoryImageCache.get(imageUrl); // 从内存缓存中获取图片
                break;
            case DISK_CACHE_TYPE:
                cacheBitmap = mDiskImageCache.get(imageUrl); // 从磁盘缓存中获取图片
                break;
        }

    可以看到,无论是获取缓存还是保存缓存,都需要进行判断,不仅麻烦还容易出错,试想一下,如果这时我们需要ImageLoader支持双缓存,即优先使用内存缓存,当内存缓存中没有时,我们需要使用文件缓存(在实际应用中,图片加载框架一般都是双缓存的,这样既能保证加载速度,又能尽可能的减少图片的下载),那么应该怎么办呢?难道还是和添加文件缓存一样,在ImageLoader中再加入一种缓存内型?显示,这种方式是不合理的,不仅让代码变得难以维护,而且扩展性极差,这个时候,开闭式原则就派上用场了。

    开闭式原则的定义:软件中的对象应该对扩展是开放的,但是,对修改是关闭的。软件开发过程中,需求是不断变化的,因为变化、升级和维护等原因需要对原有的软件代码进行修改,而一旦对原有的代码进行修改,就有可能影响到原有的模块,引起bug,因此,在软件开发过程中,我们应该尽可能通过扩展的方式实现变化,而不是修改原有的代码,当然,这是一种理想的情况,在实际的软件开发中,完全通过扩展的方式实现变化是不现实的。那么,如何让对象对扩展是开放的呢?回顾一下面向对象的三大特性:封装、继承和多态,在单一职责原则中,我们使用到了封装的特性,而继承和多态还没有使用,现在是派上用场的时候了,继承和多态的精髓在于抽象,一般来说,高层次模块不应该直接依赖低层次模块的实现细节,而应该依赖其抽象,在ImageLoader这个例子中,ImageLoader直接依赖了具体的缓存类,这就让ImageLoader和具体的缓存类紧紧的耦合在一起,我们一直强调软件开发要做到高内聚、低耦合,高内聚通过单一职责原则可以达到,而低耦合则需要依赖抽象。

    通过分析,我们不难发现无论是哪种缓存类,其都需要提供获取缓存和放入缓存的功能,即get和put,既然这样,我们为什么不将其抽象成接口呢?

    /**
     * 缓存图片接口类
     * 这个接口定义了缓存图片所需要的基本功能,缓存图片以及从缓存中获取图片
     */
    public interface ImageCache {
        public void put(String url, Bitmap bitmap); // 缓存图片
        public Bitmap get(String url); // 获取图片
    }
    

    然后具体的缓存类实现ImageCache接口:

    /**
     * ImageLoader内存缓存类,采用Lru算法
     */
    public class MemoryImageCache implements ImageCache {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        private LruCache<String, Bitmap> mLruCache = new LruCache<>(maxMemory / 4);
    
        @Override
        public void put(String url, Bitmap bitmap) {
            if (!TextUtils.isEmpty(url) && bitmap != null) {
                mLruCache.put(url, bitmap);
            }
        }
    
        @Override
        public Bitmap get(String url) {
            return mLruCache.get(url);
        }
    }
    
    /**
     * ImageLoader文件缓存
     */
    public class DiskImageCache implements ImageCache {
        private Context mContext;
    
        public DiskImageCache() {
            this.mContext = App.getContext();
        }
    
        @Override
        public void put(String url, Bitmap bitmap) {
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(DiskCacheFileUtils.getImageCacheFile(url, this.mContext));
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                CloseUtils.close(fileOutputStream);
            }
        }
    
        @Override
        public Bitmap get(String url) {
            String imageCachePath = DiskCacheFileUtils.getImageCachePath(url, this.mContext);
            if (DiskCacheFileUtils.isFileExists(imageCachePath)) {
                return BitmapFactory.decodeFile(imageCachePath);
            }
            return null;
        }
    }
    
    /**
     * ImageLoader双缓存类
     */
    public class DoubleImageCache implements ImageCache {
        private ImageCache mMemoryImageCache;
        private ImageCache mDiskImageCache;
    
        public DoubleImageCache() {
            mMemoryImageCache = new MemoryImageCache();
            mDiskImageCache = new DiskImageCache();
        }
    
        @Override
        public void put(String url, Bitmap bitmap) {
            mMemoryImageCache.put(url, bitmap);
            mDiskImageCache.put(url, bitmap);
        }
    
        @Override
        public Bitmap get(String url) {
            Bitmap bitmap = mMemoryImageCache.get(url);
            if (bitmap != null) {
                return bitmap;
            }
            bitmap = mDiskImageCache.get(url);
            if (bitmap != null) {
                return bitmap;
            }
            return null;
        }
    }
    

    上面的三个具体的缓存类,都实现了ImageCache接口,表示其具备了缓存能力,我们再来看一下在ImageLoader中如何设置缓存:

        private ImageCache mImageCache;
    
        /**
         * 设置缓存
         * @param imageCache(默认使用MemoryImageCache缓存)
         * @return
         */
        public ImageLoader setImageCache(ImageCache imageCache) {
            this.mImageCache = imageCache;
            return this;
        }

    使用缓存:

            if (mImageCache != null) { // 将图片放入缓存
        	    mImageCache.put(url, bitmap);
            }
    
            Bitmap cacheBitmap = mImageCache.get(url); // 获取缓存

    可以看到,ImageLoader并没有依赖于具体的缓存实现类,而只是依赖了缓存类接口ImageCahe,通过这种方式,我们让ImageLoader具备了可以兼容任何实现了ImageCache接口的缓存类的能力,比如,现在ImageLoader想使用双缓存,只需要调用如下代码即可:

            imageLoader.setImageCache(new DoubleImageCache());

    再比如,我们想使用其他的缓存方案,只需要定义一个缓存类,实现ImageCache接口即可:

    imageLoader.setImageCache(new ImageCache() {
                @Override
                public void put(String url, Bitmap bitmap) {
                    // 具体的放入缓存实现
                }
    
                @Override
                public Bitmap get(String url) {
                    // 具体的获取缓存实现
                    return null;
                }
            });

    通过遵循开闭式原则,我们大大提高了缓存功能的可扩展性,并且去除了ImageLoader与具体缓存类的耦合,这一切都要归功于抽象。

    里氏替换原则

    通过前面的优化,我们的ImageLoader已经大体上满足需求了,我们再来看一下里氏替换原则的定义:所有引用基类的地方都必须能够透明的使用其子类,这句话是什么意思呢,以我们的ImageLoader为例,所有引用到ImageCache的地方应该都可以替换成具体的子类对象。想象一下,如果我们的ImageCache中的ImageCache不能够被具体的缓存类所替换,那我们应该如何给ImageCahce设置缓存呢?难道还是使用原来的mCacheType的方式吗?显然不是,里氏替换原则就是给这类问题提供了指导原则,通过建立抽象,让高层次模块依赖于抽象类,在运行时在替换成具体的实现类,保证了系统的扩展性和灵活性

    依赖倒置原则

    依赖倒置原则指的是高层次模块不应该依赖于低层次模块的具体实现,两者都应该依赖其抽象,具体如下:

    1、高层次模块不应该依赖低层次模块的具体实现,两者都应该依赖其抽象;

    2、抽象不应该依赖细节;

    3、细节应该依赖抽象。

    在面向对象语言中,抽象指的是接口或者抽象类,两者都不能被实例化,而细节指的是具体的实现类。其实一句话就可以概括,面向接口编程,或者说面向抽象编程,试想一下,如果类和类之间之间依赖细节,那么这两个类将会紧紧的耦合在一起,这就意味着,修改了其中一个类,很可能需要对另外一个类也需要进行修改,并且这样也大大限制了系统的可扩展性。依赖倒置原则提供了一种解耦方式,通过抽象让类和类之间不再依赖细节,而是在具体运行时再进行替换。以我们的ImageLoader为例,通过建立抽象类ImageCache,我们让ImageLoader不再依赖于具体的缓存类,并且能够灵活的扩展使用其他的缓存功能。从上面几个原则来看,想要让系统具备更好的可扩展性,抽象似乎成为了唯一的手段。

    接口隔离原则

    接口隔离原则的定义:类间的依赖关系应该建立在最小的接口之上。接口隔离原则将非常庞大、臃肿的接口拆分成更小更具体的接口。 一个接口定义的过于臃肿,则代表它的每一个实现类都要考虑所有的实现逻辑。如果一个类实现了某个接口,也就是说这个类承载了这个接口所有的功能,维护这些功能成为了自己的职责。这就无形中增加了一个类的负担。这里有一点需要说明,接口定义要小,但是要有限度,对接口细化可以增加灵活性,但是过度细化则会使设计复杂化。同时接口的使用率不高,提高了代码的维护成本。这种极端的体现就是每个接口只含有一个方法,这显然是不合适的。以前面的ImageCache为例,图片的缓存类必须提供两个功能,放入缓存和获取缓存,所以ImageCache封装了这两个抽象方法,而不应该再进行细分。我们再举一个接口隔离的例子,我们在文件缓存类中用到了FileOutputStream,在Java中,在使用了可关闭对象后,需要调用其close方法对其进行关闭:

        public void put(String url, Bitmap bitmap) {
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(DiskCacheFileUtils.getImageCacheFile(url, this.mContext));
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                 if (fileOutputStream != null) { // 关闭fileOutputStream对象
                    try {
                        fileOutputStream .close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                 }
            }
        }

    我们可以看到这段代码的可读性非常差,各种try...catch,并且,在Java中,类似FileOutputStream这种需要关闭的对象有很多,难道我们每次使用时都要加上这种判断吗?有没有什么办法可以优化呢?答案是肯定的,在Java中,这种需要关闭的对象都继承了Closeable接口,表示这个对象是可以关闭的,Closeable接口的定义如下:

    public interface Closeable extends AutoCloseable {
        public void close() throws IOException;
    }

    我们可以建立一个工具类来专门处理继承了Closeable接口的类对象的关闭处理:

    public class CloseUtils {
        public static void close(Closeable closeable) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    这样,我们就可以将关闭FileOutputStream的代码修改为:

        CloseUtils.close(fileOutputStream);

    并且这个工具类适用于关闭所用继承了Closeable接口的对象。

    通过前面的学习,我们发现这几大原则可以总结为下面几个关键点:单一职责、抽象、最小化。在实际开发中,我们要灵活的运行这几大原则。

    迪米特原则

    迪米特原则的定义:一个对象应该对其他对象有最小的了解。迪米特原则也称作最小知道原则,即类和类直接应该建立在最小的依赖之上,一个类应该对其依赖的类有最小的了解,即只需要知道其所需要的方法即可,至于其内部具体是如何实现的则不用关心。迪米特原则的目的是减少类和类之间的耦合性,类和类之间的耦合性越大,当一个类发生修改后,会其他类造成的影响也越大。以前面的ImageLoader为例,使用者在用ImageLoader加载图片时,应该只需要和ImageLoader打交道,而不用关心具体的图片时如何下载、缓存以及显示的,并且我们在封装ImageLoader类时,还应该只将一些必要的方法设置为public方法,这些public方法表示提供给使用者使用的方法,比如加载图片和设置缓存,而对于其他的方法应该设置为private,将其隐藏起来。迪米特原则总结来说就是通过最小了解来降低类之间的耦合。

    总结

    在这篇文章中,我们通过设计一个简易的图片加载框架来说明面向对象六大原则的应用,六大原则指的是单一职责原则、开闭式原则、迪米特原则、里氏替换原则、依赖倒置原则以及接口隔离原则其中,单一职责原则是指一个类应该是一组相关性很高的函数和数据的封装,这是为了提高程序的内聚性,而其他五个原则是通过抽象来实现的,目的是为了降低程序的耦合性以及提高可扩展性。六大原则的目的是为了让程序达到高内聚、低耦合,提高可扩展性的目的,其实现手段是面向对象的三大特性:封装、继承以及多态。

    展开全文
  • 面向对象六大原则

    万次阅读 多人点赞 2015-11-30 00:10:44
    1、优化代码的第一步——单一职责原则单一职责原则的英文名称是Single Responsibility Principle,简称SRP。它的定义是:就一个类而言,应该仅有一个引起它变化的原因。简单来说,一个类中应该是一组相关性很高的...
  • 点击上方“方志朋”,选择“置顶或者星标”你的关注意义重大!这是设计模式系列开篇的第一篇文章。也是我学习设计模式过程中的总结。这篇文章主要讲的是面向对象设计中,我们应该遵循...
  • Java面向对象设计的六大原则

    千次阅读 2018-05-17 12:00:58
    这篇文章主要讲的是面向对象设计中,我们应该遵循的六大原则。只有掌握了这些原则,我们才能更好的理解设计模式。我们接下来要介绍以下6个内容。单一职责原则——SRP开闭原则——OCP里式替换原则——LSP依赖倒置原则...
  • 1.面向对象三大特性六大原则

    千次阅读 2018-04-04 12:48:17
    JAVA是一门面向对象的语言,那么其面向对象主要有以下几个特性和原则:面向对象三大特性六大原则面向对象的三大特性是"封装、"多态"、"继承",五大原则是"单一职责原则"、"...
  • 面向对象六大原则解析 面向对象六大原则: 在面向对象编程时有六大原则: l 单一职责原则 l 里氏替换原则 l 依赖倒置原则 l 开闭原则 l 接口隔离原则 l 迪米特原则 在java中与其说是面向对象编程,不如说是...
  • 面向对象程序设计(OOP)的六大原则是我对《Android源码设计模式解析与实战》的读后笔记。要设计出灵活又便于维护的软件,必须要求我们的设计能力与代码质量高,也就是我们所谓的编程思想。因此,我们需以面向对象的...
  • 面向对象的三大特性和六大原则

    千次阅读 2018-04-22 23:11:43
    一、三大特性封装: 一个类封装了数据以及操作数据的代码逻辑体。定义了数据的可访问属性(私有、公有)...二、六大原则单一功能原则 : 每个类型(包括接口和抽象)功能要求单一,只负责一件事情。 开放封闭原则...
  • Java面向对象知识点总结(全)

    千次阅读 多人点赞 2020-12-13 10:16:10
    原则 使对象以外的部分不能随意存取对象的内部数据,从而有效的避免了外部错误对它的“交叉感染”。 数据隐藏特性提升了系统安全性,使软件错误能够局部化,减少查错和排错的难度。 2、类 定义 类就是对象的...
  • 面向对象六大原则——接口隔离原则

    万次阅读 多人点赞 2018-08-13 10:54:15
    什么是接口隔离原则(Interface Segregation Principle, ISP)  接口对于Java开发者来说都不陌生,它几乎存在于每一个Java程序中,是抽象的代名词。在讲接口隔离原则之前,先说说接口,接口分为以下两种: - 实例...
  • 面向对象设计六大基本原则

    千次阅读 2020-12-22 23:20:34
    面向对象设计模式六大基本原则 本篇开始介绍面向对象设计思想 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录面向对象设计模式六大基本原则前言一、pandas是什么?二、使用步骤1.引...
  • 面向对象六大原则——开闭原则

    千次阅读 2018-08-13 10:55:33
     开闭原则Java中最基础的设计原则,它指导我们如何建立一个稳定的,灵活的系统。 - 定义:一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。 - 为什么使用开闭原则: 在程序的生命周期内,因为变化,...
  • 三、设计模式的六大原则(SOLIDD) 1、开闭原则(Open Close Principle,OCP) OCP的意思是,软件应该对扩展开放,对修改关闭。也就是说,在程序需要进行拓展的时候,不能去修改原有的代码,而是应该通过扩展...
  • 面向对象六大原则——依赖倒置原则

    万次阅读 多人点赞 2018-08-13 10:56:49
    什么是依赖倒置原则(Dependence Inversion Principle, DIP)  依赖倒置原则的包含如下的三层含义: - 高层模块不应该依赖低层模块,两者都应该依赖其抽象 - 抽象不应该依赖细节 ...在Java语言中,抽象就是指...
  • Java面向对象设计模式

    万次阅读 2017-05-02 14:17:36
     ——可复用面向对象软件的基础  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 ...
  • 面向对象程序设计(OOP)的六大原则是我对《Android源码设计模式解析与实战》的读后笔记。要设计出灵活又便于维护的软件,必须要求我们的设计能力与代码质量高,也就是我们所谓的编程思想。因此,我们需以面向对象的...
  • 学习了何红辉、关爱民写的《Android设计模式》,对于面向对象六大原则有进一步的理解,特此根据自己的理解记录总结一下 什么是开闭原则 一个类、模块、函数等应该对于扩展是开放的,但是对于修改是封闭的,简单说...
  • java开发六大基本原则

    万次阅读 多人点赞 2017-11-27 10:12:49
    设计模式之六大原则(转载)  关于设计模式的六大设计原则的资料网上很多,但是很多地方解释地都太过于笼统化,我也找了很多资料来看,发现CSDN上有几篇关于设计模式的六大原则讲述的比较通俗易懂,因此转载过来。 ...
  • 16个目标文件 内容索引:Java源码,初学实例,二进制,文件复制 Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员...
  • java面向对象最全入门笔记(通俗易懂,适合初学者)

    万次阅读 多人点赞 2019-11-14 12:00:29
    面向对象的三特征 封装 (Encapsulation) 继承 (Inheritance) 多态 (Polymorphism) 编程思想: 面向过程:做某件事情都需要自己亲历亲为,按照步骤去完成 面向对象:做某件事情不需要自己亲历亲为,只需指定特定的...
  • Java面向对象编程六大基本原则

    千次阅读 2016-12-19 19:10:23
    《Android源码设计模式解析与实战》 面向对象六大原则
  • 面向对象设计的六大原则

    千次阅读 2019-12-09 23:56:18
    1、单一职责原则(Single ...软件中的对象(类、模块、函数等)对于扩展是开放的,但是对于修改是封闭的。因为扩展只是增加新的类、函数、模块等,不会影响原有的功能,但是修改就有可能会动到以前的逻辑从而...
  • 面向对象六大原则----开闭原则

    千次阅读 2016-07-27 17:59:31
    Java面向对象编程六大原则: 单一职责原则 英文名称是Single Responsibility Principle,简称SRP 开闭原则 英文全称是Open Close Principle,简称OCP 里氏替换原则 英文全称是Liskov Substitution ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,303
精华内容 12,121
关键字:

java面向对象六大原则

java 订阅