软件设计模式—基础

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 高内聚,低耦合(对于面向对象来说):

高内聚:如果类中的方法是一组相关的行为,则称类是高内聚的。
低耦合:不要让一个类含有太多的其他类的实例的引用。

高内聚低耦合的理解——来自“bell1991”的博客

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 注释

虚线连接,解释说明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值