文章目录
1. 软件设计模式简述
1.1 定义
标准定义:设计模式是从许多的软件包系统中总结出的成功的可用的设计方法。
理解:将可重用的,在不同项目中相似性高的代码总结成一套方法
1.2 四要素
1.名称(高度概括)
2.问题(交代什么环境下什么时候使用)
3.方案(组成部分(例如用到了哪些类,类与类之间如何调用))
4.效果(能做什么)
1.3 分类
根据范围\根据目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法 | (类)适配器 | 模板方法、解释器 |
对象模式 | 单例、原型、抽象工厂、建造者 | 代理、(对象)适配器、桥接、装饰、外观、享元、组合 | 策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录 |
1.3.1 根据目的来分
1.创建型模式(将对象创建与对象的使用分离)Gof 5 种
2.结构型模式(类和对象按照布局组成大的结构)Gof 7 种
3.行为型模式(类和对象之间相互协作共同完成)Gof 11种
1.3.2 根据作用范围来分
1.类模式(类与子类的继承关系)(静态)
2.对象模式(对象间组合聚合的关系)(动态)
1.3.3 tip
Gang of Four(GoF) 四人组
1995 年,艾瑞克·伽马(ErichGamma)、理査德·海尔姆(Richard Helm)、拉尔夫·约翰森(Ralph Johnson)、约翰·威利斯迪斯(John Vlissides)等 4 位作者合作出版了《设计模式:可复用面向对象软件的基础》
2. 面向对象的基本原则
用到 抽象类 和 接口
2.1 知识点回顾
2.1.1 使用抽象类时注意:
1.抽象类不能实例化
2.抽象类的非抽象子类,需要重写父类的抽象方法
2.1.2 使用接口时注意:
1.方法只能是抽象方法
2.类实现接口,即且必须重写接口中的所有方法
3.接口回调
2.1.3 e.g.1(接口回调)
接口回调:举个例子,老师给你一张试卷,我们叫接口。你拿到试卷之后,填写了你的姓名和答案。然后你告诉老师做好了。老师拿到试卷,给你打完分之后,将试卷给你,你就看到分数了。这就是一个完整的接口回调。老师是A,学生是B,试卷是接口C。首先B拿到接口C,B–C,答题。我们可以理解为互值操作
public interface C{
public void TestList();
}
public class A implements C{
public void TestList(){
System.out.println("题的答案时250")
}
}
public class Example{
public static void main(String[] args){
C B;
B = new A();
B.TestLIst();
}
}
2.2 面向抽象的原则
面向抽象、面向接口编程
2.2.1 e.g.2(面向抽象求体积)
举个例子:求柱体体积:
拼音命名不好,这里是方便理解-链接来自14期—王闯
//抽象的形状类
public abstract class XingZhuang{
public abstract double getArea();
}
//用户要圆底,就继承抽象类
public class Yuan extends XingZhuang{
double r;
Yuan(double r){
this.r=r;
}
public double getArea(){
return r*r*3.14;
}
}
//求体积
public class ZhuTi{
XingZhuang di;
double gao;
ZhuTi(XingZhuang di,double gao){
this.di=di;
this.gao=gao;
}
public double getVolum(){
return di.getArea*gao;
}
}
//测试类
public class Test{
public static void main(String[] args){
XingZhuang di = new Yuan(2);
ZhuTi yuanzhu = new ZhuTi(di,2);
System.out.println(yuanzhu.getVolum);
}
}
2.3 开闭原则
2.3.1 定义
对软件实体的扩展开放(开)、对修改关闭(闭)
理解:就是在需求改动时,不通过修改现有的代码,而是扩展。
2.3.2 实现方法
抽象化是实现开闭原则的关键
通过“抽象约束、封装变化”来实现
2.3.3 e.g.2 在开闭原则中的体现
拿上面哪个求柱体面积来举例
上述除了测试类有三个类:形状类(abstract)、圆形类、柱体类
需求变化了,要增加一个矩形,只需要继承形状类,其他代码均无改变。
e.g.3(开闭原则例子)
//获取知识interface
public interface IReader{
public String getContent();
}
//类实现接口,需要重写接口的所有方法
//通过接口的实现类——书
public class Book implements IReader{
public String getContent(){
return "从书中得到知识";
}
}
//接口的实现类——报纸
public class Newspaper implements IReader{
public String getContent(){
return "获得报纸的信息";
}
}
//学生类
public class Student{
public void read(IReader ireader){
System.out.println(ireader.getContent());
}
}
//测试类
public class demo{
public static void main(String[] args){
Student student = new Student();
//两个接口类型的变量
IReader newspaper;
newspaper = new Newspaper();
Ireader book;
book = new Book();
student.read(book);
student.read(newspaper);
}
}
2.4 里氏替换原则
2.4.1 定义
所有引用基类的地方必须能透明的使用其子类的对象
2.4.2 应用
在使用继承时,子类中尽量不要重写父类的方法
tip:继承让实际上让两个类的耦合性增强了
2.5 单一职责原则
2.5.1 面向对象软件设计追求的目标
高内聚、低耦合
单一职责可以看作高内聚、低耦合的引申
2.5.2 定义
一个类有且仅有一个引起它变化的原因,否则就应该被拆分
2.5.3 e.g.4(调制解调器)
把调制解调器的功能用接口的方式实现,实际上调制解调器有两个功能(连接和数据通信)
interface Modem{
public void dial(String pno);//拨号
public void hangup();//挂断
public void send();//发送数据
public char recv();//接收数据
}
此时这两个职责耦合在一起了。将其拆分:
interface DataChannel{
public void send(char c);
public void recv();
}
interface Connection{
public void dial(String pno);
public void hangup();
}
2.5.4 作用
单一职责使类的复杂度降低了,代码可读性增加、维护性变强、变更引起的风险也会降低。
核心就是控制类的粒度的大小,将对象解耦、提高内聚性。
2.5.5 tip
职责的如何去分需要设计人员具有较强的分析能力和重构能力
大学生的工作管理程序
2.6 依赖倒置原则
核心思想:面向接口编程,不是面向实现编程
2.6.1 面向对象 与 面向过程 设计依赖的区分
面向过程设计:把一个大的系统分成小的系统,大的系统依赖小的系统形成的
面向对象设计:高层模块就不依赖底层模块了,高层模块和底层模块依赖的是抽象,这也是依赖倒置原则的定义。
2.6.1 定义
高层模块不应该依赖低层模块,两者均依赖于抽象;抽象不应该依赖细节
2.6.2 实现方法
1.每个类尽量提供接口或者抽象类,或者两者都具备
2.变量声明类型尽量是接口或者抽象类
3.类应该从抽象来派生,而不是通过具体类
4.尽量遵守里氏替换
2.6.3 e.g.5(顾客购物、与e.g.3几乎相同)
//商店接口
public interface Shop{
public String sell();
}
//商店接口实现类——Nike店
public class Nike implements Shop{
public String sell(){
return "您购买了Nike的商品";
}
}
//商店接口实现类——Adidas店
public class Adidas implements Shop{
public String sell(){
return "您购买了Adidas的商品";
}
}
//消费者类
public class Custom{
public void Shopping(Shop shop){
System.out.println(shop.sell());
}
}
//测试类
public class demo1{
public static void main(String[] args) {
Custom custom1 = new Custom();
Shop nike;
nike = new Nike();
custom1.Shopping(nike);
custom1.Shopping(new Adidas());
}
}
2.7 接口隔离
不要把想法集中再一个类或接口上
核心:接口尽量小
2.7.1 定义
客户端不应该被强迫依赖于它不使用的方法
2.7.2 理解-e.g.6(接口隔离类图举例)
遵守接口隔离设计后:
2.8 迪米特法则
别称:最少知道原则
2.8.1 定义
定义:只与你的朋友交谈。
“朋友”指的是:(当前对象本身(this)、当前对象的实例变量直接引用的对象、当前对象所创建的对象、以参数形式传入当前对象中的对象等),这些对象同当前对象存在关系,就可以直接访问这些对象的方法。
2.8.2 大致用法
大体讲的意思呢,我用不到的方法,你整成私有的就完事了
2.9 多用组合少用继承原则
2.9.1 方法复用最常用技术
方法复用:类继承(白盒复用) 和 对象组合(黑盒复用)
(黑白盒自己按照测试去理解吧)
2.9.2 对象组合
理解:对象a组合对象b,a可以委托b调用他的方法
优点:弱耦合关系
缺点:系统中对象过多
2.9.3 e.g.7(通过对比理解继承 和对象组合)
这个例子中有一个动物类,让狗类继承动物类(白盒复用),创建一个鸟类(黑盒复用)
//动物类
public class Animals{
//心脏跳动(private)
//子类是不能继承私有的属性和方法,只能在类的内部使用
private void heartbeat(){
System.out.println("Heart Beating!");
}
//呼吸(public)
public void breath(){
heartbeat();//调用心脏跳动的方法
System.out.println("Are Breathing!");
}
//血液流动(public)
public void bloodflow(){
System.out.println("Blood is folwing!");
}
}
//狗类继承动物类(白盒复用)
public class Dogs extends Animals{
//继承后呢,狗就具有了动物呼吸和血液流动的方法
//再定义一个狗自己的方法,汪
public void bark(){
System.out.println("Dog Is Barking!");
}
}
//直接定义一个鸟类(使用Animals的breath方法就是对象组合)
public class Birds{
private Animals a;//用Animals类型的变量来代替继承(引用类型变量)
public Birds(Animals a){//用构造方法来给引用类型赋值
this.a = a;
}
/*
我们鸟也需要一个呼吸的方法,但是又没有继承Animals
我们怎么与Animals里的呼吸方法建立关系?
答:让Animals类的对象成为Birds类的一部分
*/
public void breath(){
a.breath();//a是引用类型的
}
//自身的飞的方法
public void fly(){
System.out.println("Birds Is Flying");
}
}
//测试类
public class Test{
public static void main(String[] args){
//继承的复用
Dogs dog = new Dogs();
dog.breath();
dog.bark();
//组合的复用
Animals animal = new Animals();
Birds bird = new Birds();
bird.breath();
bird.fly();
}
}
2.9.4 tip
利用组合要比用继承,耦合度降低了
耦合度降低了,继承还需要
要多使用组合,少用继承
2.9.5 高内聚,低耦合(对于面向对象来说):
高内聚:如果类中的方法是一组相关的行为,则称类是高内聚的。
低耦合:不要让一个类含有太多的其他类的实例的引用。
3 回顾UML
3.1 类图:
好文当赏——如何使用StarUML——来自“Boom_Man”的博客
使用StarUML画类图——来自“Faith_chao”的博客
3.1.1 类:
名字层:类的名字
变量层:访问权限(公有(+),私有(-),保护(#),友好(啥也没))+变量名+数据类型
操作层:和变量层相似
3.1.2 接口
除了名字层(<<接口名>>),其他的和类一样
3.2 类和类之间的关系
3.2.1 泛化关系
在Java内指的是继承关系
空心三角实心箭头,子类指向父类
3.2.2 实现关系
一个类实现一个接口
空心三角虚线箭头,类指向接口
3.2.3 关联关系
类与类之间的关系
定义:A类中成员变量是B类中声明的变量
实心箭头,A的UML指向B的UML
3.2.4 依赖关系
也是类与类之间的关系
理解:A类中某个方法的参数(或局部变量) 用B类的类型来声明
A依赖于B
画法:虚线箭头
3.2.5 聚合关系
是关联关系的一种
关联的两个对象是平等的,聚合是一边不平,整体与部分的关系,实现上区别不大。
理解:描述着,两者之间虽有关系,但又对各自的存在又无影响
用空心菱形箭头表示
3.2.6 组合关系
是一种强依赖的聚合关系
整体和部分不可分
3.2.7 注释
虚线连接,解释说明