设计模式——UML建模的重要知识类图关系和基本的设计原则小结

引言

UML建模我想很多人可能在学习到的时候都觉得不重要,没有意识到重要性,但是当你拥有一些实际的项目经验和深受维护升级、性能的困扰时候,你会后悔当初为啥没有重视设计模式,没有灵活运用设计模式,而设计模式最本质的思想就是面向对象、面向接口,所以众多模式之间存在着一些相似之处,需要结合具体的业务区分析,到底使用哪种设计模式,而UML建模则可以提供一些依据。

一、UML类图关系概述

UML主要定义了泛化(继承)实现组合聚合关联依赖六种关系,他们之间关系耦合程度依次加强( 泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖)

二、泛化(继承)

泛化一种一般与特殊、一般与具体之间关系的描述,是类与类或者接口与接口之间最常见的关系,具体描述建立在一般描述的基础之上,并对其进行了扩展。通俗说是指的是一个类(称为子类、子接口)继承另外的一个类(称为基类、父接口)的功能,并可以增加它自己的新功能的能力(但父类的非私有属性和方法,子类会无条件继承,这可能导致造成父类的属性和方法在某些子类中不适用的问题,而且继承只能单根继承,无法让一个类拥有多个类的方法和属性),在Java中此类关系通过关键字extends明确标识,UML中用空心三角形箭头的实线连接,箭头指向基类
这里写图片描述

class BaseClass{
public void operate(){}
}
class ConcreateClass extends BaseClass{
@override
public void operate(){}
}

三、实现

实现一种类与接口之间最常见的关系,表示类是接口所有特征和行为的实现,一般通过类实现接口来描述是一个class类实现interface接口(可以是多个)的功能,同时也是Java实现“多继承”的一种机制,,在Java中此类关系通过关键字implements明确标识,UML**用空心三角形箭头的虚线连接,箭头指向接口**
这里写图片描述

interface Interface {
    public void operate();
}

class InterfaceImpl implements Interface {
    public void operate(){}
}

四、依赖(Dependency)

依赖是一种使用的关系即一个类的实现需要另一个类的协助(尽量不使用双向的互相依赖),而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A,在Java中一般表现为类A中的方法需要类B的实例作为其参数或者变量,而类A本身并不需要引用类B的实例作为其成员变量,UML用虚线箭头连接,箭头指向被使用者
这里写图片描述

class Client{
    public void depend(UsedObj obj){

    }
}

class UsedObj{}

五、关联(Association)

关联类与类之间的联接,它使一个类可以访问另一个类的属性和方法,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的且双方的关系一般是平等的、关联可以是单向、双向的(双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。),在Java中被被关联类B以类属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量,UML用带普通箭头的实心线连接,指向被拥有者
这里写图片描述

class ConnectObj{
    private AssociatedObj obj;
}

class AssociatedObj {

}

六、聚合(Aggregation)

聚合关联关系的一种特例,他体现的是整体与部分、拥有的关系即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享比如计算机与CPU、公司部门与员工的关系等,表现在代码层面主要体现在成员变量上。UML用带空心菱形的实心线连接,菱形指向整体
这里写图片描述

class Department{
    Employee emp;
}

class Employee{

}

七、组合(Composition)

组合也是关联关系的一种特例,他体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合;他同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如你和你的心脏,表现在代码层面和关联关系是一致的主要体现在成员变量上,只能从语义级别来区分,UML用带实心菱形的实线连接,菱形指向整体
这里写图片描述

class People{
    Heart heart;
}

class Heart{

}

八、软件设计的六大原则

1、单一职责原则

单一职责原则(Single Responsibility Principle,SRP)——就一个类而言,应该仅有一个引起它变化的原因,永远不要让一个类有多个改变的理由,一个类只应该做和一个任务相关的业务,不应该把过多的业务放在一个类中完成,简而言之就是一个类中应该是一组相关性很高的数据、函数封装,这往往是重构的第一步。

2、开闭原则

开闭原则(Open Close Principle,OCP)是Java语言中最基础的设计核心原则,指一个软件系统中的对象(类,模块,方法等) 应该对扩展开放,对修改封闭,开闭的核心就是抽象,将相同的部分封装到一起,使代码重用即闭,把不同的也拿到另一边,便于功能的扩展即开,所以当需求改变的时候我们尽量通过扩展的方式来实现,尽量避免修改原来的代码,因为根据”2-8原则”修改原来的代码可能会引发新的问题,所以要尽量确保原有代码不出问题的话,开闭原则会是一个有效的帮手。

3、迪米特原则

迪米特原则(Low of Demeter,LOD),又叫作最少知识原则(Least Knowledge Principle,“Only tall to your immediately friends”只与最直接的朋友交流,那么映射到编程中就是两个对象具有耦合关系就相当于是朋友)指是一个对象应该对其他对象有最少的了解和相互作用,简而言之就是一个类应该对自己需要耦合或调用类知道得最少,类内部如何实现与使用者无关,只需要知道一个调用方法即可,比如A类要调用B类的a,b,c三个方法,迪米特法则就是只调用方法a,由a去调用b和c,说白了就是尽量让A类少去调用别类的方法

public class Room {
    public float price;

    public Room(float price) {
        this.price = price;
    }
}

class Mediator{
    List<Room> list=new ArrayList<>();
    public Mediator(){
        for(int i=0;i<5;i++){
            list.add(new Room(200*i+200));
        }
    }
    public List<Room> getAllRoms(){
        return list;
    }
}

class Tenant{
    public float price;

    public void rentRoom(Mediator mediator){
        List<Room> rooms=mediator.getAllRoms();
        for (Room room: rooms) {
            if(isSuitable(room)) {
                System.out.println("成功租到房间了" + room);
                break;
            }
        }
    }

    private boolean isSuitable(Room room) {
        if(room.price<200){
            return true;
        }else {
            return false;
        }
    }
}

如上所述是以中介租房为例,作为房客只需要告诉中介房间的价格,中介找到房之后告知就行,但是很明显上面的设计是存在很大问题的:租客Tenant不仅依赖了中介Mediator,还偷偷地和房间Room交互,导致Tenant和Room耦合较高Room变化时会导致Tenant也跟着变化,而Mediator也可能需要变化,耦合逻辑较复杂,因此根据迪米特原则必须解耦,进行以下重构

class Mediator{
    List<Room> list=new ArrayList<>();
    public Mediator(){
        for(int i=0;i<5;i++){
            list.add(new Room(200*i+200));
        }
    }
    public Room rentOut(float price){
        for (Room room: list) {
            if (isSuitable(room)){
                return room;
            }
        }
        return null;
    }

    private boolean isSuitable(Room room) {
        if(room.price<200){
            return true;
        }else {
            return false;
        }
    }
}

class Tenant{
    public float price;
    public void rentRoom(Mediator mediator){
       mediator.rentOut(price);
    }
}

4、依赖倒转法则:

依赖倒转原则(Depenence Inversion Principle,DIP)其实就是只面向接口编程,其实,应该遵循以下三点:

  • 高层模块不应该依赖于低层模块,二者都应该依赖于抽象

  • 抽象不应该依赖于细节,细节应该依赖于抽象

  • 面向抽象编程,不要面向具体编程

所谓抽象就是指接口抽象类细节就是实现类(实现接口和继承抽象类产生的类)。高层模块就是调用端,低层模块就是具体实现类。

5、里氏替换原则

里氏替换原则(Liskov Substitution Principle,LSP)
父类出现的地方,子类一定可以替换,简而言之,所有引用积累的地方必须能透明底使用其子类。不过,尽量使用聚合/组合达到代码复用,少使用继承代码复用

6、接口隔离原则

接口隔离原则(InterfaceSegregation Principles,ISP),客户端不应该依赖他不需要的接口,类间的关系应该建立在最小的接口上。简而言之,使用专门的接口比使用统一的接口要好,不要让用户面对自己用不到的方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
UML类图 UML(Unified Modeling Language),即统一建模语言,是图标式软件设计语言。 类图(Class diagram)是最常用的UML图,显示类、接口以及它们之间的静态结构和关系,用于描述系统的结构化设计类图基本的元素是类或者接口。 第1页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第1页。 类的UMLUML类图显示类的三个组成部分,第一是Java中定义的类名,第二个是该类的属性,第三个是该类提供的方法。 第一层为类的名称,第二层是类的属性,第三层表示的是类的方法或称为操作。 一个类图的类名是必须的 第2页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第2页。 类的UML图 注意:属性和方法之前附加的可见性修饰符, "+"表示public,"-"表示private,"#"表示protected。省略这些修饰符表示具有package(包)级别的可见性。冒号后边表示数据的类型或方法的返回值类型。 如果是抽象类,类名以斜体表示。 第3页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第3页。 UML类图关系 第4页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第4页。 接口UML表示 第5页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第5页。 依赖关系:虚线+箭头 第6页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第6页。 关联关系:空心的菱形+实线箭头 第7页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第7页。 组合关系:实心的菱形+实线箭头 第8页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第8页。 实线+空心的三角形,起始端是子类,空心三角形指向终点端的父类。 泛化关系: 第9页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第9页。 实现关系 实现关系UML表示法:虚线+空心三角形。 第10页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第10页。 发现变化,并封装变化 在软件设计之初,需要发现所要开发软件中可能存在或已经存在的"变化",然后利用抽象的方式对这些变化进行封装。抽象是没有具体的代码实现,抽象代表了一种可扩展 。 参阅教材例9.1 第11页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第11页。 单一职责原则和最少知识原则 在单一职责(Single Responsibility Principle, 简称为SRP)中,就一个类而言,应该仅有一个引起它变化的原因。也就是说,不要把变化原因各不相同的职责放在一起。 第12页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第12页。 单一职责原则和最少知识原则 最少知识原则(Least Knowledge Principle, 简称为LKP)又叫迪米特法则(Law of Demeter,简写为LoD),就是说一个对象应当对其他对象有尽可能少的了解。就像我国古代老子所说的"使民无知"和"小国寡民"的统治之术,"是以圣人之治,虚其心,实其腹,弱其志,常使民无知无欲。"以及 "小国寡民……邻国相望,鸡犬之声相闻,民至老死,不相往来"。 第13页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第13页。 开放-封闭原则 所谓"开放-封闭原则"(Open-Closed Principle),也称"开-闭原则",就是让设计对扩展开放,对修改关闭。也就是说,不允许更改的是系统的抽象层,而允许更改的是系统的实现层。高层模块不应该依赖低层模块,抽象不应该依赖细节,使系统设计更为通用、更为稳定。面向抽象编程,这里的抽象主要指的是抽象类或接口。 第14页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第14页。 开放-封闭原则 "开放-封闭原则"实质上是指当一个设计中增加新的模块时,不需要修改现有模块。 第15页/共30页 Java面向对象程序设计杨晓燕面向对象基本原则和模式全文共30页,当前为第15页。 子类型能够替换基类型原则 子类型能够替换基类型原则也叫里氏代换原则(Liskov Substitution Principle ,简称LSP),里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现,且程序运行正常。 特

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值