在线目录生成工具

目录

0 前言

个人学习、整理和记录面向对象相关知识点用。其中大部分内容来自以下地址,表示感谢。
cyc-面向对象思想
面向对象设计之魂的六大原则
设计模式(一)——面向对象六大原则

1 三大特性

封装、继承、多态。

封装

利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏的细节,只保留一些对外的接口使其与外部发生联系。用户无需关心对象内部的细节,但可以通过对象对外提供的接口来访问对象。

优点:
1.减少耦合:可以独立地开发、测试、优化、使用、理解和修改;
2.减轻维护的负担:可以更容易被理解,并且在调试的时候可以不影响其他模块;
3.有效地调节性能:可以通过剖析来确定哪些模块影响了系统的性能;
4.提高软件的可重用性;
5.降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块却有可能是可用的。

示例代码


public class Person {

    private String name;
    private int gender;
    private int age;

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender == 0 ? "man" : "woman";
    }

    public void work() {
        if (18 <= age && age <= 50) {
            System.out.println(name + " is working very hard!");
        } else {
            System.out.println(name + " can't work any more!");
        }
    }
}

继承

继承实现了IS-A关系,例如Cat和Animal就是一种IS-A关系,因此Cat可以继承自Animal,从而获得Animal非private的属性和方法。
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
Cat可以当做Animal来使用,也就是说可以使用Animal引用Cat对象。父类引用指向子类对象称为向上转型。

Animal animal = new Cat();

继承特点:
1.子类拥有父类非private的属性和方法;
2.子类可以拥有自己的属性和方法,即子类可以对父类进行拓展;
3.子类可以用自己的方式实现父类的方法(重写)。

继承的缺点:
1.父类变,子类就必须变;
2.继承破坏了封装,对于父类而言,他的实现对子类来说是透明的;
3.继承是一种强耦合关系。

多态

多态分为编译时多态和运行时多态:编译时多态主要指方法的重载;运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定。
运行时多态,需要满足三个条件:1.继承;2.覆盖(重写);3.向上转型。
下面的代码中,乐器类(Instrument)有两个子类:Wind和Percussion,他们都覆盖了父类的play方法,并且在main方法中使用父类Instrument来引用Wind和Persussion对象。在Instrument引用调用play()方法时,会执行实际引用对象所在类的play()方法,而不是Instrument类的方法。

public class Instrument {

    public void play() {
        System.out.println("Instument is playing...");
    }
}


public class Wind extends Instrument {

    public void play() {
        System.out.println("Wind is playing...");
    }
}


public class Percussion extends Instrument {

    public void play() {
        System.out.println("Percussion is playing...");
    }
}


public class Music {

    public static void main(String[] args) {
        List<Instrument> instruments = new ArrayList<>();
        instruments.add(new Wind());
        instruments.add(new Percussion());
        for(Instrument instrument : instruments) {
            instrument.play();
        }
    }
}


out>>>>
Wind is playing...
Percussion is playing...

2 类图

以下内容,使用PlanUML绘制

泛化关系(Generalization)

用来描述继承关系,在java中使用extends关键字。

@startuml

title Generalization

class Vihical
class Car
class Trunck

Vihical <|-- Car
Vihical <|-- Trunck

@enduml

实现关系(Realization)

用来描述实现一个接口,在java中使用implements关键字。

@startuml

title Realization

interface MoveBehavior
class Fly
class Run

MoveBehavior <|.. Fly
MoveBehavior <|.. Run

@enduml

聚合关系(Aggregation)

表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还在。

@startuml

title Aggregation

class Computer
class Keyboard
class Mouse
class Screen

Computer o-- Keyboard
Computer o-- Mouse
Computer o-- Screen

@enduml

组合关系(Composition)

和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在。比如公司和部门,公司没了部门也就没了。但是公司和员工就属于聚合关系。

@startuml

title Composition

class Company
class DepartmentA
class DepartmentB

Company *-- DepartmentA
Company *-- DepartmentB

@enduml

关联关系(Association)

表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用1对1,多对1,多对多这种关联关系来表示。比如学生和学校就是关联关系,一个学校可以有好多学生,但是一个学生只属于一个学校,因此这是一种多对1的关系,在运行之前就可以确定。

@startuml

title Association

class School
class Student

School "1" - "n" Student

@enduml

依赖关系(Dependency)

和关联关系不同的是,依赖关系是在运行过程中起作用的。A类和B类是依赖关系主要有三种形式:
1.A类是B类方法的局部变量;
2.A类是B类方法的参数;
3.A类向B类发送消息,从而影响B类发生变化。

@startuml

title Dependency

class Vihicle {
    move(MoveBehavior)
}

interface MoveBehavior {
    move()
}

note "MoveBehavior.move()" as N

Vihicle ..> MoveBehavior

Vihicle .. N

@enduml

类之间的关系

3 六大原则

1.单一职责原则(SRP,Single Responsibility Principle);
2.开闭原则(OCP,Open Close Principle);
3.里氏替换原则(LSP,Liskov Substitution Principle);
4.依赖倒置原则(DIP,Dependence Inversion Principle);
5.接口隔离原则(ISP,Interface Segregation Principle);
6.迪米特原则(LOD,Law of Demeter)。

1.单一职责原则

定义:就一个类而言,应该仅有一个引起它变化的原因。
也就是说一个类只负责一项职责,一个类中应该是一组相关性很高的函数及数据的封装。

2.开闭原则

定义:一个软件实体应当对拓展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行拓展。
开闭原则提倡一个类一旦完成,后续增加新的功能就不应该通过修改这个类来实现,而是通过继承,增加新的类。这个原则比较虚,也很难做到完全遵循,需要在开发中自行体会。

3.里氏替换原则

定义:所有引用父类的地方,必须能透明地使用其子类的对象。
也就是说,软件系统中所有用到某个类的地方,替换成它的子类后仍然能够正常运行。这个原则依赖面向对象的继承性和多态性,这个原则我们有意无意中使用的比较多。

4.依赖倒置原则

定义:抽象不应该依赖于细节,细节应该依赖抽象。即要针对接口编程,而不是针对实现编程。
该原则有以下关键点:
1.高层模块不应该依赖底层模块。两者都应该依赖其抽象;
2.抽象不应该依赖细节;
3.细节应该依赖抽象
其中,抽象是指java中的抽象类或者接口;细节是指java中的具体实现类;高层模块是指java中的调用类;底层模块是指java中的实现类。
模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系。

5.接口隔离原则

定义:使用多个专门的接口,而不是 使用单一的总接口。即客户端不应该依赖那些它不需要的接口。
意思是接口应该尽可能的小,从而到达解耦的目的,使系统容易重构。

6.迪米特原则

定义:一个软件实体应当尽可能少地与其他实体发生相互作用。
一个类应该对自己需要调用的类知道得最少,类的内部如何实现,如何复杂都与调用者或者依赖者没有关系,调用者或者依赖者只需要知道它需要的方法即可。

总结:
六大原则全是以构建灵活、可扩展、可维护的软件系统为目的,所以说它的重要性高与设计模式,应该是程序员时刻印在脑子里的东西,设计模式也是它的具体实践而已。六大原则比较抽象,很难在日常开发中100%地遵循所有的原则。但是,也应该把这六大原则作为日常开发的理论指导,只要你或多或少的遵循这六大原则,那么写出来的代码就不会太烂,慢慢地也就能理解那些看起来吊炸天的设计模式的意图和思路。