设计模式:一种对软件设计中普遍存在(反复出现)的各种问题所提出的解决方案。
设计模式的目的:设计模式可以帮助开发人员更好地组织代码结构,提高代码重用性、可读性、可维护性、耦合性、内聚性。
经典面试题:
七大设计原则核心思想
能够以类图的说明设计原则
在项目实际开发中,你在哪里使用到了ocp原则
。。。。。
设计模式分为:
七大原则
23种设计模式
使用在算法和框架中,例如Spring框架就使用了多种的设计模式。
设计模式原则:程序员在编程时,应遵守的原则,也是各种设计模式的基础(即:设计模式为什么这样进行设计)
七大原则:
单一职责原则
接口隔离原则
依赖倒转(倒置)原则
里氏替换原则
开闭原则
迪米特法则
合成复用原则
对于类来说,即一个类只应该负责一项职责。(各司其职)
目的:
降低类的复杂度,一个类只负责一项职责
提高可读性
降低变更代码引起的风险
通常情况下,我们应该遵守单一职责原则。但是职责是死的,逻辑是活的,当逻辑足够简单的时候,我们可以适当的违反单一原则(只有类中的方法数量足够少,可以在方法级别保持单一职责原则)。
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在它的最小接口上。
个人理解:尽量让类只实现自己需要的最小接口。
为啥要有这个接口隔离原则呢?
1. 避免不必要的依赖: 当一个接口中包含了大量方法时,实现该接口的类可能会因为需要实现不相关的方法而产生不必要的依赖关系。这增加了代码的耦合度,使得系统更加脆弱。 2. 提高灵活性: 通过遵循接口隔离原则,可以将一个庞大的接口拆分成多个小接口,使得客户端只需依赖自己需要的接口,从而提高系统的灵活性和可维护性。 3. 降低修改成本: 遵循接口隔离原则可以降低修改接口的成本。如果一个接口需要修改,那么只有实现这个接口的类受到影响。如果一个接口过于臃肿,修改接口可能会导致很多类需要作出改动,增加了系统的维护成本。 4. 增强可读性和可理解性
依赖倒转原则的介绍:
1、高层模块不应该依赖底层模块,两者都应该依赖其抽象 2、抽象不应该依赖细节,细节应该依赖抽象 3、依赖倒转的中心思想是面向接口编程 4、依赖倒转原则的设计理念:对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。 5、使用接口或抽象类的目的是制定规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。 在Java中,抽象指的是接口或抽象类,细节就是具体的实现类。
下面就是依赖倒转原则的例子:
interface IReceiver{
String getInfo();
}
class Email implements IReceiver {
public String getInfo(){
return "电子邮件信息:hello,world";
}
}
class WeiXin implements IReceiver {
public String getInfo(){
return "微信信息:hello,world";
}
}
class person {
public void receiver ( IReceiver receiver){
System.out.println(receiver.getInfo());
}
}
依赖关系传递的三种方式
1、接口传递(上述的代码)
2、构造方法传递
interface IOpenAndClose{
public void open();
}
interface ITV {
public void play();
}
class OpenAndClose implements IOpenAndClose {
public ITV tv; //成员
public OpenAndClose(ITV tv){
this.tv = tv; //构造方法
}
}
3、setter方式传递
interface IOpenAndClose{
public void open();
}
interface ITV {
public void play();
}
class OpenAndClose implements IOpenAndClose {
public ITV tv; //成员
public void setTv(ITV tv){
this.tv = tv;
}
public void open(){
this.tv.play();
}
}
注意事项和细节
1、底层模块尽量都要有抽象类或接口,或者两者都有,程序的稳定性更好 2、变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化 3、继承时遵循里氏替换原则
关于oo中的继承性的思考和说明:
1、继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。 2、继承在给程序设计带来便利的同时,也带来了弊端,比如说:带来侵入性,程序可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。 3、问题提出,我们该如何正确使用继承 =》 里氏替换原则
里氏替换原则:子类对象应当能够替换掉父类对象,并且程序的行为不应该发生变化。
里氏替换原则的目的:确保继承关系的正确性和稳定性。
当一个类被用作其子类的类型时,它应该表现出与其父类相同的行为和特性,这样才能保证系统的可靠性和可维护性。
对于里氏替换原则个人理解:
1、子类应保留父类的特性 2、子类可以扩展父类的行为,但不能删除、修改父类的行为(尽量不去重写父类的方法) 3、子类应该遵循父类定义的规范 4、里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当情况下,可以通过聚合、组合、依赖来解决问题。 5、里氏替换原则就是确保子类能够透明地替换父类,并且在程序中不会引起意外的行为
介绍:
1、开闭原则是编程中最基础、最重要的设计原则 2、ocp原则是指:一个软件实体,如类、模块、函数应该对扩展开发(对提供方),对修改关闭(使用方),用抽象构建框架,用实现扩展细节。 3、软件需要变化时,**尽量通过扩展实体的行为来实现变化,而不是通过修改已有的代码来实现变化**(重点) 4、编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则
介绍
一个类对自己依赖的类知道的越少越好
1、一个对象应该对其他对象保持了解最少 2、类与类关系越密,耦合度越大 3、迪米特法则(又称对少知道原则),即一个类对自己依赖的类知道的越少越好。就是或,对于被依赖的类,不管多么复杂,都尽量将逻辑封装在类的内部,对外除了提供public方法,不对外泄露任何信息 4、更简单的定义:只与直接朋友通信 5、直接朋友 的 定义:每个对象都会与其他对象有耦合关系,如果两个对象有耦合关系,说明对象之间是朋友关系。我们称成员变量、方法参数、返回值的类为直接朋友;其他在局部变量中的类不是直接朋友。 就是说陌生的类最好不用以局部变量的形式出现在类的内部。 迪米特法则的主要目的是降低软件系统中对象之间的耦合度,提高系统的可维护性、可扩展性和灵活性。
例子:
假设有一个学校管理系统,包含学生、教师、课程等对象,它们之间可能存在如下关系: 学生和教师之间的关系 学生对象需要了解自己的教师信息,但不需要知道其他教师的信息。这可以通过在学生类中添加一个教师属性,只保存自己的教师信息,而不直接访问教师类来实现。 学生和课程之间的关系 学生对象需要知道自己所选课程的信息,但不需要知道其他课程的信息。同样可以通过在学生类中添加一个课程属性,只保存自己所选课程的信息,而不直接访问课程类来实现。 教师和课程之间的关系 教师对象需要知道自己所教授的课程信息,但不需要知道其他课程的信息。也可以通过在教师类中添加一个课程属性,只保存自己教授课程的信息,而不直接访问课程类来实现。
介绍:概念就是:尽量使用合成/聚合的方式,而不是使用继承。
如果有A、B两个类,如果B需要使用A的方法。
我们不应该想着让B去继承A类,而是可以将A作为一个属性引入在B中。
尽量使用对象的组合关系,而不是继承关系来达到代码复用的目的。
找出应用中可能需要变化的地方,把他们独立出,不要和那些不需要变化的代码混在一起
针对接口编程,而不是针对实现编程
为了交互对象之间的松耦合设计而努力
是一种用于软件系统分析和设计的语言工具,用于帮助软件开发人员进行思考和记录思路的结果。
类图是描述的是:类与类之间关系
类之间的关系:
表示依赖(使用)
如果A类用到了B类,说明A依赖于B(A -> B)
小结:
1、类中使用到对方 2、是类的成员属性 3、是方法的返回参数 4、是方法接收的参数类型 5、方法中使用到
表示泛化(继承),是依赖关系的一种特例
小结:
1、泛化关系就是继承关系 2、如果A类继承了B类,就称A和B存在泛化关系
表示实现,他也是依赖关系的特例。
表示关联(一对一,一对多,多对多),他是依赖的特例
具有单向关系和双向关系。
A类中有B,B类中没有A,单向关系
双向关系同上
聚合(一种弱的拥有关系)。表示整体于部分的关系,整体和部分可以分开。是关联关系的特例。
例子: 假设有一个汽车(Car)类和一个引擎(Engine)类。汽车拥有一个引擎,但引擎可以独立存在,并且可以被多辆汽车共享
组合(一种强的拥有关系),就是整体和部分不可分割。
例子:现在假设汽车(Car)类中的引擎(Engine)对象是不可或缺的,没有引擎就无法创建汽车。