查看原文
其他

设计模式系列(2):图文并茂详解UML类图

mbb 一行Java 2022-08-09
设计模式系列 第 2 篇 
上一篇:设计模式系列(开篇):啥是设计模式?
文末点击“阅读全文”,查看系列汇总

什么是UML?

UML(Unified Modeling Language,统一建模语言),是一种用于软件系统分析和设计的语言工具,用于帮助软件开发人员进行思考和记录思路的结果

UML本身是一套符号的规定,通过这些符号,来描述软件模型中各个元素之间的关系;比如类、接口、实现、泛化、依赖、组合、聚合等

UML图的目的

上面有介绍,UML是一种语音,语言的核心作用就是用来交流;不过他交流的方式并不是以传统意义上的说进行的,而是以图形加文字的方式进行;其最终的目的就是将真实的系统给抽象,然后以图文可视化的方式表达出来,使软件设计人员沟通更简明,进一步缩短了设计时间,减少开发成本。

这里的还有另外一个主要的目的,为了后续设计模式的过程中,结合UML类图,能更好的理解。

UML的分类

  • 用例图
  • 静态结构图
    • 类图
    • 对象图
    • 包图
    • 组件图
    • 部署图
  • 动态行为图
    • 时序图
    • 协作图
    • 交互图
    • 状态图
    • 活动图

说明:

类图是描述类与类之间的关系,是UML图中最核心的部分;后续的设计模式讲解,也主要是通过类图来协助我们理解。那么这里也就主要讲解类图的部分了。

类图常用标识符

实体

描述UML图
简单类
接口
  • 简单的类图示例

    public class User {
        // 用户id
        private Integer id;
        // 用户名
        public String name;
        // 地址
        protected String addr;
        
        // 设置id
        public void setId(Integer id) {
            this.id = id;
        }
        // 获取用户名
        public String getName() {
            return name;
        }
        // 获取地址
        public String getAddr() {
            return addr;
        }
    }
  • 类图

    • 第一层:类名

    • 第二层:属性名

      分为了三个部分:

                最左边为访问权限+(public)-(private)#(protected)

                中间为属性名称

                右边为属性的类型

    • 第三层:方法

      结构和属性类似

关系

图标关系(Relation)
泛化(继承)(Generalization)
实现(Realization)
依赖(Dependency)
聚合(Aggregation)
组合(Composite)
关联(Association)

泛化(继承)

泛化关系又称之为继承关系(Generalization),用来描述类与类之间的父子关系;父类又称之为基类,子类称之为派生类;

父类主要用来描述了一类事物的公有属性或行为;

继承关系中,子类继承父类的所有功能,父类所具有的属性、方法,子类应该都有。子类中除了与父类一致的信息以外,还允许包括额外的信息。

例如:不管什么材质的门,都具备开门或关门的行为;否则,就不能称之为门了;所以他的材质和开关门的行为就可以定义为父类,其他所有的门都将继承自这个基类;

  • 继承关系符

  • 类图

  • 代码实现

    父类

    public class Door {
        // 材质
        public String material;

        // 开门
        public void open(){
            System.out.println(material+"门打开了");
        }
        // 关门
        public  void close(){
            System.out.println(material+"门关上了");
        }
    }

    木门

    public class WoodenDoor extends Door{
        public WoodenDoor(){
            this.material = "木制";
        }
    }

    玻璃门

    public class GlassDoor extends Door{
        public GlassDoor(){
            this.material = "玻璃";
        }
    }
  • 测试

    public class Test {
        public static void main(String[] args) {
            Door woodenDoor = new WoodenDoor();
            woodenDoor.open();
            woodenDoor.close();
            Door glassDoor = new GlassDoor();
            glassDoor.open();
            glassDoor.close();
        }
    }

    运行结果

实现(Realization)

用来表达类与接口之间的关系;

接口是一个方法的集合,在实现关系中,实现类需要实现接口中定义的所有方法;

接口主要用来定义一类对象中,部分拥有的行为;

例如:所有的门都拥有开关门的行为,但是并不是所有的门都有门铃的行为,对于这种不是所有对象都有用的行为,我们就可以将其定义为接口;对象想拥有该行为,就实现对于的接口;

延续上一个示例,假定木门有门铃,玻璃门没有门铃,实现如下:

  • 实现关系符

  • 类图

  • 代码示例

    • 父类

      public class Door {
          // 材质
          public String material;

          // 开门
          public void open(){
              System.out.println(material+"门打开了");
          }
          // 关门
          public  void close(){
              System.out.println(material+"门关上了");
          }
      }
    • 接口

      public interface DoorBell {
          void bell();
      }
    • 木门

      public class WoodenDoor extends Door implements DoorBell{
          public WoodenDoor(){
              this.material = "木制";
          }

          public void bell() {
              System.out.println(material+"门的门铃响了:咚咚咚...");
          }
      }
    • 玻璃门

      public class GlassDoor extends Door {
          public GlassDoor(){
              this.material = "玻璃";
          }
      }
    • 测试代码

      public class Test {
          public static void main(String[] args) {
              Door woodenDoor = new WoodenDoor();
              woodenDoor.open();
              woodenDoor.close();
              Door glassDoor = new GlassDoor();
              glassDoor.open();
              glassDoor.close();

              // 判断有没有实现门铃的接口
              if(woodenDoor instanceof DoorBell){
                  // 实现了 说明具备门铃的功能 然后就按门铃
                  ((DoorBell) woodenDoor).bell();
              }

              // 同上
              if(glassDoor instanceof DoorBell){
                  ((DoorBell) glassDoor).bell();
              }
          }
      }

      测试结果

依赖关系(Dependency)

只要一个类中用到了其他类,那他们之间就存在依赖关系

例如:一个门(Door)的对象中包含了一个锁对象,要想开这个锁(Lock),就需要传入一个对应的钥匙(Key)对象。

  • 依赖关系符

  • 示例代码

    • public class Lock {
      }
    • 钥匙

      public class Key {
      }
    • public class Door {
          Lock lock = new Lock();

          public void open(Key key){

          }
      }
  • 类图

    如图可以看出,Door分别依赖了Lock和Key对象。


关联关系(Association)

关联关系实际上就是类与类之间的联系,他属于依赖关系的特例

关联关系具有导航性,即单向关联双向关联

关联不仅存在一对一的关系,同样也存在一对多,多对多的关系;

例如:一个门对应一个门牌号,一个门牌号对应一个门;

  • 关系符

  • 类图

  • 示例代码

    • public class Door {
          DoorPlate doorPlate = new DoorPlate();
      }
    • 门牌

      public class DoorPlate {
          Door door = new Door();
      }

  • 类图

    上图可以看出,在存在关联关系的同时,也存在着依赖关系,所以也就印证了上面说的,关联关系是依赖关系的一种特例。

聚合关系(Aggregation)

聚合关系表示一种整体与部分的关系;且这种整体与部分的关系是可以分开的,聚合属于关联关系的特例;所以他具有导航性和多重性。

例如:门和锁的关系,锁是门的一个组成部分,但是没有锁,对门的特性不会带来任何影响;也就是说,没有锁,门依然还是个门。

  • 示例代码

    • public class Lock {
      }
    • 如下代码,Lock对象是通过Set方法赋值进去的,所以,表示这个门,可以有锁,也可以没有锁,并不是一种强关联关系

      public class Door {
          private Lock lock;

          public void setLock(Lock lock){
              this.lock = lock;
          }
      }
  • 类图

组合(Composite)

组合是聚合的一种特例,只是他们关系是一种强关联关系,是一种不可分割的关系

例如:门和门框的关系,门没有办法脱离门框独立存在于哪里;所以,有门的地方,必定会有个门框;

  • 示例代码

    • 门框

      public class DoorFrame {
      }
    • public class Door {

          public DoorFrame doorFrame;

          public Door(){
              doorFrame = new DoorFrame();
          }
      }
  • 类图

总结

到这里,常用到的UML实体及关系就说的差不多了,这并不是UML的全部,但是他是UML中最常用的部分;几乎可以解决日常工作、学习的90%以上的场景;

上面都是零碎的,结合上面所讲的细节,绘制了一个完整的包含6种关系的UML图,来协助更好的理解


另外,推荐一个超赞的免费作图工具:好工具:超强的全行业全种类作图软件 不仅功能超全,而且还可以免费使用。


END



点击👇名片,关注公众号,回复  资料  
获取大厂面试资料1T+视频教程电子书等各类精品资料

最近开发整理了一个用于速刷面试题的小程序;其中收录了上千常见面试题及答案(包含基础并发JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud、消息队列等多个类型),欢迎您的使用。QQ交流群:912509560


-----  推荐阅读  -----
面试官:双重检查单例(DCL)要不要加volatile?详解来了
Docker部署SpringBoot的2种方式
设计模式系列(开篇):啥是设计模式?
MySQL 5.7和8.0谁的性能更优?
一文吃透MyBatis-Plus常用API,包教包会

👇点击"阅读原文",查看连载汇总(持续更新中)

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存