设计模式
[TOC]
七大原则
单一职责原则
对类来说,一个类应该只负责一项职责,如类A负责两个不同职责:职责1和职责2.当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将A的粒度分解为A1和A2.
接口隔离原则
客户端不应该依赖于它不需要的接口,即一个类对另一个类的依赖一个建立在最小的接口上(接口拆分)
- 类A类B如果
依赖倒转原则
- 高层模块不应该依赖于底层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 依赖倒转的中心思想时面向接口编程
- 依赖倒转原则时基于这样的设计原理:相对于细节的多变性,抽象的对象要稳定的多.以抽象为基础搭建订单架构比以细节为基础的架构要稳定的多.在java中,抽象指的是接口或抽象类
- 使用接口或抽象类的目的时制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成/
依赖关系传递的三种方式
-
接口传递
interface IOpenAndClose{ void open(); } interface Imple { void play(); } class OpenAndClose implements IOpenAndClose{ //通过传入方法参数传入实现类 publick void open(Imple imple){ imple.play(); } }
-
构造方法传递
interface IOpenAndClose{ void open(); } interface Imple { void play(); } class OpenAndClose implements IOpenAndClose{ public Imple imple; //通过构造方法传入实现类 public OpenAndClose(Imple imple){ this.imple=imple; } public void open(){ this.imple.play(); } }
-
setter方法传递
interface IOpenAndClose{ void open(); } interface Imple { void play(); } class OpenAndClose implements IOpenAndClose{ public Imple imple; //通过setter方法传入实现类 public SetImple(Imple imple){ this.imple=imple; } public void open(){ this.imple.play(); } }
注意事项和细节
- 底层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好.
- 变量的声明类信息尽量是抽象类或接口,这样我们的变量引用和实际对象键,旧存在一个缓冲层,利于程序扩展和优化.
- 继承时遵循里氏替换原则
里氏替换原则
继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,但如果子类对这些已经实现的方法任意需修改,就会对整个继承体系造成破坏.
继承在给程序设计带来方便的同时,也带来了弊端,比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类锁继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有设计到子类的功能都有可能长生故障.
子类尽量不要重写父类的方法
继承实际上让两个类耦合性增强,在适当情况下,可以通过聚合,组合,依赖来解决问题.
class A{
//两数相减
publci int func1(int num1 ,int num2){
return num1 - num2;
}
}
class B extends A{
//无意将方法重写为两数相加
publci int func1(int a ,int b){
return a + b;
}
//B实现的功能,目的返回两数相减再加9,实际a+b+9
publci int func2(int a ,int b){
return func1(a,b)+9;
}
}
通过聚合修改
class Base{}
class A extends Base{
public void func1(int num1,int num2){return num1 + num2;}
}
//不在继承自A类
class B extends Base{
private A a = new A();
//任然重写了A的方法
public int func1(int a,int b){return a+b;}
public int func2(int a,int b){return func1(a+b)+9;}
//任然可以使用原本的A的方法
public int func3(int a,int b){return this.a.func1(a,b);}
}
开闭原则 ocp
最基础,最重要的设计原则
一个软件实体如类,模块和函数应该对扩展开放(==提供者==),对修改关闭(==使用者==).用抽象搭建跨框架,用实现扩展细节
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化
-
编程中遵循其他原则,以及使用设计模式的目的就是遵循拟开闭原则
class 绘图类{ fun(){ //接收对象,判断类型运行绘图 //运行1 //运行2 //当需要添加新,没有对修改关闭,需要新的运行3 //运行3 } } class Base{} class 绘图类1 extends Base{} class 绘图类2 extends Base{} //新增绘图类 class 绘图类3 extends Base{}
修改后
class 绘图类{ do{} } class Base{ //继承需要实现的抽象方法 public abstract void do{} } class 绘图类1 extends Base{do{1}} class 绘图类2 extends Base{do{2}} //新增绘图类 class 绘图类3 extends Base{do{3}}
迪米特原则
一个对象应该对其他对象保持着最少的了解(例:下订单)
类与类关系越密切,耦合度越大
迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好.也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部.对外处理提供订单public方法,不对外泄露任何信息
简单定义:只与直接订单朋友通信
-
==直接朋友==:每个对象都会与其他的对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系.耦合的方式很多,依赖,关联,组合,聚合等.其中,我们称出现成员变量,方法参数,方法返回值中的类为直接朋友,而出现在局部变量中的类不是直接的朋友.也就是说,陌生的类最好不要以局部变量的形式出现子类的内部
public class Lishitihuan { public static void main(String[] args) { SchoolManager schoolManager = new SchoolManager(); schoolManager.printAllEmployee(new CollegeManager()); } } //学校总部员工 class Employee { private String id; public void setId(String id) { this.id = id; } public String getId() { return id; } } //学院员工 class CollegeEmployee { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } } //管理学院员工的管理类 class CollegeManager { //返回学院的所有员工 public List<Employee> getAllEmployee() { List<Employee> list = new ArrayList<Employee>(); //添加10个员工 for (int i = 0; i < 10; i++) { Employee emp = new Employee(); emp.setId("学院员工" + i); list.add(emp); } return list; } } //SchoolManager的直接朋友类CollegeEmployee //学校管理类 class SchoolManager { //SchoolManager的直接朋友类: 返回值 public List<CollegeEmployee> getAllEmployee() { List<CollegeEmployee> list = new ArrayList<CollegeEmployee>(); //添加10个总部员工 for (int i = 0; i < 5; i++) { CollegeEmployee emp = new CollegeEmployee(); emp.setId("学校总部员工" + i); list.add(emp); } return list; } //输出学校总部员工的信息 //SchoolManager的直接朋友类: 参数 public void printAllEmployee(CollegeManager collegeManager) { //获取学院员工 此处不是成员变量,返回值,参数,所有不是直接朋友 // List<CollegeEmployee> list = this.getAllEmployee(); System.out.println("-----------学院员工------------"); for (CollegeEmployee employee : list) { System.out.println(employee.getId()); } //学校总部员工 List<Employee> list2 = new CollegeManager(). getAllEmployee(); System.out.println("-----------学校总部员工------------"); for (Employee employee : list2) { System.out.println(employee.getId()); } } }
修改后
//管理学院员工的管理类 class CollegeManager { //放回学院的所有员工 public List<Employee> getAllEmployee() { List<Employee> list = new ArrayList<Employee>(); //添加10个员工 for (int i = 0; i < 10; i++) { Employee emp = new Employee(); emp.setId("学院员工" + i); list.add(emp); } return list; } public void printEmployee(){ //获取学院员工 此处不是成员变量,返回值,参数,所以不是直接朋友 // List<Employee> list = this.getAllEmployee(); System.out.println("-----------学校员工------------"); for (Employee employee : list) { System.out.println(employee.getId()); } } } //学校管理类 class SchoolManager { //SchoolManager的直接朋友类: 返回值 public List<CollegeEmployee> getAllEmployee() { List<CollegeEmployee> list = new ArrayList<CollegeEmployee>(); //添加10个总部员工 for (int i = 0; i < 5; i++) { CollegeEmployee emp = new CollegeEmployee(); emp.setId("学校总部员工" + i); list.add(emp); } return list; } //输出学校总部员工的信息 //SchoolManager的直接朋友类: 参数 public void printAllEmployee(CollegeManager sub) { sub.printEmployee(); //学校总部员工 List<CollegeEmployee> list2 = getAllEmployee(); System.out.println("-----------学校总部员工------------"); for (CollegeEmployee employee : list2) { System.out.println(employee.getId()); } } }
迪米特法则的核心是==降低==类之间的耦合
合成复用原则
- 尽量使用合成或聚合的方式,而不是继承
UML
-
建模语言
类之间的六种关系
链接:https://blog.csdn.net/qq_29379115/article/details/78332487
https://www.jianshu.com/p/ca8b1b08b420
一、继承关系(泛化关系)
继承指的是一个类(称为子类、子接口)继承另外的一个类(父类、父接口)的功能,并可以增加它自己的新功能的能力。在java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。
img
二、实现关系
实现指的是一个Class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在java中实现关系通过implements明确标识,在设计时一般没有争议性。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。
三、依赖关系
简单地理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性、临时性、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面为,类B作为参数被类A在某个method方法中使用。在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。
四、关联关系
关联体现的是两个类之间语义级别的强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面为,被关联类B以类的属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
五、聚合关系
聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,比如一个航母编队包括航空母舰、驱逐护卫舰、舰载飞机及核动力攻击潜艇等。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。
六、组合关系
组合也是关联关系的一种特例,它体现的是contains-a的关系,这种关系比聚合更强,也成为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,组合关系以实心菱形加实线箭头表示。
总结:
对于继承、实现这两种关系没多少疑问,它们体现的是类和类、类与接口之间的纵向关系。其他的四种关系体现的是类与类、或者类与接口之间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。
装饰者模式
装饰着模式:动态的将星星呢附加到对象上.在对象功能扩展方面,它比继承更有弹性,转世这模式也体现了开闭原则(ocp)
这里提到的==动态的将新功能附加到对象和ocp原则==,
Component:主体,比如衣服
ConcreteComponent:具体的主类
Decorator:装饰者
[图片上传失败...(image-81bd42-1595647854838)]
//看idea