一.设计模式相关内容介绍
1.设计模式概述
1.1软件设计模式概念
软件设计模式,又叫设计模式,在软件设计过程中的一些不断发生的问题,以及该问题的解决方案,也就是说,它是解决特定问题的一系列套路,是前辈们代码设计经验的总结,具有一定的普遍性,可以反复使用。
1.2学习设计模式必要性
设计模式是都面向对象设计的实际应用,是对类的封装性/继承性/多态性以及类的关联关系和组合关系的充分理解。
优点:
1)可以提高程序员的思维能力,编程能力和设计能力
2)使程序设计更加标准化,代码编制更加工程化,大大提高软件开发效率,缩短软件的开发周期
3)使设计的代码的可重用性高,可读性强,可靠性高,灵活性好,可维护性强。
1.3设计模式分类
创建型模式:用于描述怎样创建对象,它的主要特点是将对象的创建和使用进行分离。(解耦)
结构性模式:用于描述如何将类或对象按照某种布局组成更大的结构
行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象无法独立完成的任务,以及 怎样分配职责。
2.UML图
UML又叫统一建模语言,特点是统一,简单,图形化(主要)能表达软件设计中的动态与静态信息
UML从目标系统的不同角度出发,定义了用例图,类图,对象图,状态图,活动图,时序图,协作图,构件图,部署图等9中图。
2.1类图概述
类图显示的是模型的静态结构,特别是模型中存在的类,类的内部结构以及他们与其他类的关系等。类图不显示暂时性的信息,类图是面向对象建模的重要组成部分。
2.2.类图的作用
在软件工程中,类图是一种静态的结构图,描述了类的集合,类的属性,和其他类的关系,简化人们对系统的理解。
类图是系统分析和设计阶段的重要产物,是系统编码和测试的重要模型。
2.3类图表示法
在URM类图中,类使用包含类名,类属性和类方法,且带有分割线的矩形来表示,比如:
上图中的符号表明这个属性或者方法的可见性(相当于对应JAVA中的修饰符),“+”表示public,“-”表示private, "#"表示protected,完整结构:
属性的完整表示方式:可见性 名称:类型[=缺省值]
方法的完整表示方式:可见性 名称(参数列表)[:返回类型]
#上面的中括号中的内容是可选的
例子:
2.3.2类与类之间的关系的表示方法
2.3.2.1 关联关系
关联关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系。比如老师和多个学生。关联分为单项,双向,自关联。
单联:
双向:
#注意这个没有箭头,表示双向
自关联:
一个带箭头指向自身的线表示。上图的意思就是Node类包含类型为Node的成员变量,也就是“由自己包含自己”。
2.3.2.2 聚合关系
聚合关系是关联关系的一种,是强关联关系,是整体和部分之间的关系。成员对象脱离整体也可可以独立存在。
2.3.2.3 组合关系
和聚合区别,如果整体不存在了,部分也不存在
2.3.2.4 依赖关系
临时性,某个类的方法,耦合性低
2.3.2.5 继承关系
注意线是实线
2.3.2.6 实现关系
线是虚线,上面的要写Interface
3.软件设计原则
再软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据6条原则来开发程序,从而提高软件开发效率,节约软件开发成本和维护成本。
1)开闭原则
对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果,要想达到这样的效果,我们需要使用接口和抽象类。
案例:
举一个搜狗输入法换皮肤的例子
创建一个抽象类AbstractSkin
package com.zxd.demo1;
public abstract class AbstractSkin {
public abstract void display();
}
创建一个继承类DefaultSkin 当作是默认皮肤
package com.zxd.demo1;
public class DefaultSkin extends AbstractSkin {
@Override
public void display() {
System.out.println("默认皮肤");
}
}
创建一个继承类HeiMaSkin 当作是黑马皮肤
package com.zxd.demo1;
public class HeiMaSkin extends AbstractSkin {
@Override
public void display() {
System.out.println("黑马皮肤");
}
}
创建一个继承类SouGouSkin 当作是搜狗输入法,里面写一个特有方法,用于设置皮肤的方法
package com.zxd.demo1;
import javafx.scene.control.Skin;
public class SouGouSkin extends AbstractSkin {
private AbstractSkin skin;
@Override
public void display() {
skin.display();
}
public void setSkin(AbstractSkin skin){
this.skin = skin;
}
}
创建一个实习类,里面又main方法进行测试
package com.zxd.demo1;
public class Client {
public static void main(String[] args) {
//创建搜狗输入法对象
SouGouSkin souGouSkin = new SouGouSkin();
//创建皮肤对象
DefaultSkin defaultSkin = new DefaultSkin();
//将默认皮肤放到搜狗输入法
souGouSkin.setSkin(defaultSkin);
//输出打印
souGouSkin.display();
//之后设置为黑马皮肤
souGouSkin.setSkin(new HeiMaSkin());
//输出打印
souGouSkin.display();
}
}
//这样写的好处是,当你要增加皮肤的时候,你会发现不需要改变其他的类,只需要在写一个类去继承接口即可,在修改的时候,也只需要改测试类就行,这就是扩展开放,修改关闭。
2)里氏转换原则
任何基类可以出现的地方,子类一定可以出现,通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能,子类继承父类时,除了添加新的方法完成新增功能以外,尽量不要重写父类的方法。(如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较繁琐时,程序运行出错的概率会非常大)
创建一个长方形的类
package com.zxd.demo2;
public class Rectangle {
private double length;
private double wight;
public void setLength(double length) {
this.length = length;
}
public void setWight(double wight) {
this.wight = wight;
}
public double getLength() {
return length;
}
public double getWight() {
return wight;
}
}
创建一个正方形的类去继承它
package com.zxd.demo2;
public class Square extends Rectangle {
@Override
public void setLength(double length) {
super.setLength(length);
super.setWight(length);
}
@Override
public void setWight(double wight) {
super.setWight(wight);
super.setLength(wight);
}
}
创建一个测试类
package com.zxd.demo2;
public class RectangleDemo {
public static void main(String[] args) {
//创建长方形对象
Rectangle rectangle = new Rectangle();
//设置长和宽
rectangle.setLength(20);
rectangle.setWight(10);
//调用resize方法进行扩宽
resize(rectangle);
//打印输出扩宽后的结果
printLengthAndWidth(rectangle);
System.out.println("==========");
//创建一个正方形
Square square = new Square();
square.setLength(10);
//进行扩宽
resize(square);
//打印
printLengthAndWidth(square);
}
//扩宽方法
public static void resize(Rectangle rectangle){
//只要宽比长小就增大,知道宽大于长才停止扩宽
while(rectangle.getLength()>=rectangle.getWight()){
rectangle.setWight(rectangle.getWight()+1);
}
}
//打印长和宽
public static void printLengthAndWidth(Rectangle rectangle){
System.out.println(rectangle.getLength()+" => "+rectangle.getWight());
}
#上面的问题就是长方形扩宽是没问题的,但是如果你是正方形的扩宽,就是无线进行下去,直到溢出
;
解决:
创建一个接口
package com.zxd.demo2.after;
public interface Quadrilateral {
double getLength();//获取长
double getWidth();//获取宽
}
创建一个长方形类实现接口
package com.zxd.demo2.after;
public class Rectangle implements Quadrilateral {
private double length;
private double width;
@Override
public double getLength() {
return length;
}
@Override
public double getWidth() {
return width;
}
public void setLength(double length) {
this.length = length;
}
public void setWidth(double width) {
this.width = width;
}
}
创建一个正方形类实现接口
package com.zxd.demo2.after;
public class Square implements Quadrilateral {
private double side;//边长
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
@Override
public double getLength() {
return side;
}
@Override
public double getWidth() {
return side;
}
}
创建一个测试类
package com.zxd.demo2.after;
import com.zxd.demo2.after.Rectangle;
public class RectangleDemo {
public static void main(String[] args) {
//创建长方形对象
Rectangle rectangle = new Rectangle();
rectangle.setLength(20);
rectangle.setWidth(10);
System.out.println("1");
resize(rectangle);
System.out.println("2");
printLengthAndWidth(rectangle);
}
//扩宽方法
public static void resize(Rectangle rectangle){
//只要宽比长小就增大,知道宽大于长才停止扩宽
while(rectangle.getLength()>=rectangle.getLength()){
rectangle.setWidth(rectangle.getWidth()+1);
}
}
//打印长和宽
public static void printLengthAndWidth(Quadrilateral rectangle){
System.out.println(rectangle.getLength()+" => "+rectangle.getWidth());
}
}
3)依赖倒转原则
高层模块不应该依赖底层模块,两者都应该依赖其抽象, 抽象不应该依赖细节,细节应该依赖抽象,简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。(个人理解就是面向接口编程)
创建Cpu接口
package com.zxd.demo3;
public interface Cpu {
public void run();
}
创建实现类
package com.zxd.demo3;
public class InterCpu implements Cpu{
//run方法
public void run(){
System.out.println("使用Inter处理器");
}
}
创建HardDisk接口
package com.zxd.demo3;
public interface HardDisk {
public void save(String data);
public String get();
}
创建实现类
package com.zxd.demo3;
import java.security.PublicKey;
public class XijieHardDisk implements HardDisk{
//存储数据的方法
public void save(String data){
System.out.println("希捷硬盘存储数据为:"+data);
}
public String get(){
System.out.println("使用希捷硬盘取数据");
return "数据";
}
}
创建Memory接口
package com.zxd.demo3;
public interface Memory {
public void save();
}
创建实现类
package com.zxd.demo3;
public class KingstonMemory implements Memory{
//存储数据的方法
public void save(){
System.out.println("使用金士顿内存条:");
}
}
创建一个Computer类
package com.zxd.demo3;
public class Computer {
private HardDisk hardDisk;
private Cpu cpu;
private Memory memory;
public HardDisk getHardDisk() {
return hardDisk;
}
public void setHardDisk(HardDisk hardDisk) {
this.hardDisk = hardDisk;
}
public Cpu getCpu() {
return cpu;
}
public void setCpu(Cpu cpu) {
this.cpu = cpu;
}
public Memory getMemory() {
return memory;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
public void run(){
System.out.println("运行计算机");
String s = hardDisk.get();
System.out.println("从硬盘上获取的数据是:"+s);
cpu.run();
memory.save();
}
}
测试类
package com.zxd.demo3;
public class ComputerDemo {
public static void main(String[] args) {
//创建主键对象
XijieHardDisk xijieHardDisk = new XijieHardDisk();
InterCpu interCpu = new InterCpu();
KingstonMemory kingstonMemory = new KingstonMemory();
//创建对象
Computer computer = new Computer();
//组装计算机
computer.setCpu(interCpu);
computer.setHardDisk(xijieHardDisk);
computer.setMemory(kingstonMemory);
computer.run();
}
}
#使用的是接口作为属性,这样的话,灵活性较高,扩展性好,解耦
4)接口隔离原则
客户端不应该被迫依赖于它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上。
向左边这种情况,如果你使用继承,B就有A的功能了,但是A中方法2你又不需要,是被迫继承过来的,所以采用右边,继承单个接口就可以了。
防盗接口
package com.zxd.demo4;
public interface AntiTheft {
void antiTheft();
}
防火接口
package com.zxd.demo4;
public interface Fireproof {
void fireproof();
}
防水接口
package com.zxd.demo4;
public interface Waterproof {
void waterproof();
}
创建一个黑马品牌的安全门
package com.zxd.demo4;
//黑马品牌的安全门
public class HeiMaSafetyDoor implements AntiTheft,Fireproof,Waterproof{
@Override
public void antiTheft() {
System.out.println("防盗");
}
@Override
public void fireproof() {
System.out.println("防火");
}
@Override
public void waterproof() {
System.out.println("防水");
}
}
创建一个测试类
package com.zxd.demo4;
public class Client {
public static void main(String[] args) {
HeiMaSafetyDoor heiMaSafetyDoor = new HeiMaSafetyDoor();
heiMaSafetyDoor.antiTheft();
heiMaSafetyDoor.fireproof();
heiMaSafetyDoor.waterproof();
}
}
5)迪米特法则
又叫最少知识原则,只和你的直接朋友交谈,朋友指的是:当前对象本身,当前对象的成员对象,当前对象所创建的对象,当前对象的方法参数等,这些对象同当前对象存在关联,聚合或组合关系,可以直接访问这些对象的方法。
就是找个中介,比如你要做软件,找到软件公司,然后公司安排软件工程师
创建一个明星类
package com.zxd.demo5;
public class Star {
private String name;
public Star(String name){
this.name = name;
}
public String getName(){
return name;
}
}
创建一个粉丝类
package com.zxd.demo5;
public class Fans {
private String name;
public Fans(String name) {
this.name = name;
}
public Fans() {
}
public String getName() {
return name;
}
}
创建一个公司类
package com.zxd.demo5;
//媒体公司类
public class Company {
private String name;
public Company(String name){
this.name = name;
}
public String getName() {
return name;
}
}
创建一个经纪人类
package com.zxd.demo5;
//经纪人类
public class Agent {
private Star star;
private Fans fans;
private Company company;
public void setStar(Star star) {
this.star = star;
}
public void setFans(Fans fans) {
this.fans = fans;
}
public void setCompany(Company company) {
this.company = company;
}
//和粉丝见面的方法
public void meeting(){
System.out.println(star.getName()+"和粉丝:"+fans.getName()+"见面");
}
//和媒体公司洽谈的方法
public void business(){
System.out.println(star.getName()+"和"+company.getName()+"洽谈");
}
}
创建一个测试类
package com.zxd.demo5;
public class Client {
public static void main(String[] args) {
Agent agent = new Agent();
Star star = new Star( "林青霞");
agent.setStar(star);
Fans fans = new Fans("小红粉丝");
agent.setFans(fans);
Company company = new Company("XXX公司");
agent.setCompany(company);
agent.meeting();
agent.business();
}
}
6)合成复用原则
尽量先使用组合或者聚合等关系来实现,其次才考虑使用继承关系来实现
通常类的复用分为继承复用和合成复用两种
二.创建者模式(5种)
1.单例模式
2.原型模式
3.工厂方法模式
4.抽象工厂模式
5.建造者模式
三.结构型模式(7种)
1.代理模式
2.适配器模式
3.桥接模式
4.装饰者模式
5.外观模式
6.享元模式
7.组合模式
四.行为型模式(11种)
1.模板方法模式
2.策略模式
3.命令模式
4.职责链模式
5.状态模式
6.观察者模式
7.中介者模式
8.迭代器模式
9.访问者模式
10.备忘录模式
11.解析器模式