[TOC]
UML简述
参考:第2章 UML急速入门
概述 1 2 3 4 5 6 7 8 9 10 11 12 UML的定义 UML的特点 UML2.2的分类 结构式图形 行为式图形 交互式图形 UML类图 记忆技巧 UML时序图 1、黑色的实线和实心箭头表示同步调用 2、黑色的实线和空心箭头表示异步调用 3、黑色的虚线和空心箭头就表示方法的返回值
UML类图 UML类图讲解
1 2 3 4 5 6 7 1、如果出抽象类,类名是用斜体来表示 2、"+"表示public 3、"-"表示private 4、"#"表示protected 5、"~"或者什么都不加就表示default的包权限 6、有下划线"_"表示static的属性或者是方法 7、斜体的表示的是抽象方法,既然这个类里面含有抽象方法,那么这个类也必然是一个抽象类
UML类图讲解-自上而下
1 2 3 4 5 6 7 8 《大话设计模式》 依赖关系:一般是作为一个方法的入参: 继承的关系:这里要注意的是:箭头的指向,是从子类指向父类 鸟 is a 动物 组合关系:组合关系的两个类是具有相同的生命周期的; 鸟 翅膀 关联关系:一个类把另一个类作为属性 聚合关系:这里要注意菱形和箭头的方向不要指反了,菱形是多的一方。 大雁 雁群 实现接口: 棒棒糖表示法
UML类图讲解-对比讲解
1 2 3 依赖是虚线、关联是实线 聚合是空菱形、组合是实菱形 继承是实线、实现是虚线
软件设计七大原则
参考:第3章 软件设计七大原则
开闭原则 定义:对扩展开放,对修改关闭
1 2 3 4 5 6 7 8 9 10 public interface ICourse public class JavaCourse implements ICourse 接口应该是稳定的,不应该是经常修改的。 // 打折 public class JavaDiscountCourse extends JavaCourse 我们通过了继承了基类,然后对其进行扩展,对扩展是开发的,而对修改接口和基类是关闭的 ;越是基层的模块的修改影响的范围是越大的。
依赖倒置原则 定义:高层[tom]不该依赖底层[JavaCourse]、两者都该依赖其抽象[ICourse]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 面向实现来进行编程,面向实现类来进行编程的话, 扩展性比较的差,这个就是依赖于底层的实现的 改为面向接口编程: public class JavaCourse implements ICourse public class FECourse implements ICourse public class Tom { public void studyCourse (ICourse iCourse) { iCourse.studyCourse(); } } 注入: 通过接口方法的方式来注入 tom.studyCourse(new JavaCourse()); 通过构造器的方式来注入 Tom tom = new Tom(new JavaCourse()); tom.studyCourse(); 利用set方法来进行注入 Tom tom = new Tom(); tom.setiCourse(new JavaCourse()); tom.studyCourse();
单一职责原则 定义:不要存在多于一个导致类变更的原因
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Bird 那么现在就是有问题的 ,鸵鸟不是用翅膀飞的。 这个时候,我们在原来Bird 类里面进行扩展:这个时候,是不遵循单一职责原则的 这个时候,我们按照职责的不同来进行拆分: public class FlyBird public class WalkBird 案例2: public interface ICourse 这个接口里面含有两个大块的功能:一个是获取课程的相关的信息,一个是对课程进行管理: 这个时候,我们就是可以对上面的接口进行一个拆分: public interface ICourseContent public interface ICourseManager 实现类: public class CourseImpl implements ICourseManager ,ICourseContent 要看实际的情况,不能过少的运用单一职责原则,也不能过多的使用单一职责原则,如果类过多的话,会引起来类的爆炸的现象 ;
接口隔离原则 定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface IAnimalAction { void eat () ; void fly () ; void swim () ; } public class Dog implements IAnimalAction 但狗不会飞 我们可以对上面的接口来进行细化 public interface IEatAnimalAction public interface IFlyAnimalAction public interface ISwimAnimalAction 我们在设计接口的时候,也不能分的太细,让接口过多 ;接口隔离原则在使用的时候,一定要适度,用的过多,或者过少都是不好的。
迪米特原则 定义:一个对象应该对其他对象保持最少的了解。又叫【最少知道原则】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class Course // 负责人 public class TeamLeader { public void checkNumberOfCourses (List<Course> courseList) { System.out.println("在线课程的数量是:" +courseList.size()); } } public class Boss { public void commandCheckNumber (TeamLeader teamLeader) { List<Course> courseList = new ArrayList<>(); for (int i = 0 ; i < 20 ; i++) { courseList.add(new Course()); } teamLeader.checkNumberOfCourses(courseList); } } 在Boss这个类的下达指令的方法里面,除开入参 ,出参, 还有类里面的成员变量,这些变量称为朋友,其他的都不能称为朋友,在下达指令的这个方法里面不应该和Course的这个类有任何的交互,这里就是违背了迪米特法则。 【只和朋友交流,不要和陌生人说话】 --------------------------------- 修改: public class TeamLeader { public void checkNumberOfCourses () { List<Course> courseList = new ArrayList<>(); for (int i = 0 ; i < 20 ; i++) { courseList.add(new Course()); } System.out.println("在线课程的数量是:" +courseList.size()); } } public class Boss { public void commandCheckNumber (TeamLeader teamLeader) { teamLeader.checkNumberOfCourses(); } } 在使用迪米特法则的时候,我们要区分哪些是朋友,哪些不是朋友;
里氏替换原则 定义:任何基类可以出现的地方,子类一定可以出现。 LSP(里氏替换原则)是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为
引申:子类可以扩展父类功能,但不能改变父类原有功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 开闭原则的时候,在获取打折价格,我们是这样来写的: public class JavaDiscountCourse extends JavaCourse { public Double getOriginPrice () { return super .getPrice(); } @Override public Double getPrice () { return super .getPrice()*0.8 ; } } 这里的getPrice()方法已经是重写了父类里面的非抽象方法,不符合里氏替换原则 优点:约束继承泛滥 改: public class JavaDiscountCourse extends JavaCourse { public Double getDiscountPrice () { return super .getPrice()*0.8 ; } } --------------------------- 案例2 : 描述一下长方形和正方形的关系 public class Rectangle { private long length; private long width; } public class Square extends Rectangle { private long sidelength; @Override public long getLength () { return getSidelength(); } @Override public void setLength (long length) { setSidelength(length); } } 上面的实现是不符合里氏替换原则的; 改: 四边形的接口: public interface Quadrangle { long getWidth () ; long getLength () ; } 长方形这个类来实现上面的接口 public class Rectangle implements Quadrangle 正方形: public class Square implements Quadrangle
合成复用原则 定义:尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DBConnection { public String getConnection () { return "MySQL的数据库连接" ; } } public class ProductDao extends DBConnection { public void addProduct () { String conn = super .getConnection(); System.out.println("使用" +conn+"增加产品" ); } } 现在需要再用Oracle的数据库来进行连接 改: public abstract class DBConnection { public abstract String getConnection () ; } public class MySQLConnection extends DBConnection public class OracleConnection extends DBConnection // 使用组合而不是继承!! public class ProductDao { private DBConnection dbConnection; public void setDbConnection (DBConnection dbConnection) { this .dbConnection = dbConnection; } public void addProduct () { String conn = dbConnection.getConnection(); System.out.println("使用" +conn+"增加产品" ); } } 如果我们还有再进行扩展的话,那么我们就再写上一个类 ,然后去实现DBConnection里面的抽象方法,具体的实现由调用者自己去决定new 哪一个实现的实例。