uml - 如何在 UML 对象和序列图中为同一对象分别显示引用类型和对象类型

标签 uml class-diagram sequence-diagram ooad object-diagram

enter image description here 该图显示了示例类图和序列图中这些类的对象的用法。

在上图中,实例 myCar 可以通过 ShowroomItem 的引用或接口(interface) Vehicle 的引用来引用。因此,客户驱动程序/销售工程师将获得功能访问权限。

我同意在实现阶段(例如 Java),这里不需要类型识别,我们将把 myCar 视为基类型(任一接口(interface))使用它自己的实例。

但在时序图中,(为了清楚起见)我无法指出 DrivermyCar 的引用应该是 Vehicle 并且SalesEngineer 应该属于 ShowroomItem

我在 UML 2.0 书籍中搜索,我没有找到合适的符号。根据目前的理解,我可以将其显示为 "myCar : Vehicle""myCar : ShowroomItem",但这并不表示它的汽车对象称为接口(interface).这个缺点并不强制 playMusic 在被称为 Vehcile 时不能工作。

有没有表示这种细节的符号?

由于我对提供的任何答案都不满意,我尝试添加以下内容以使问题更清楚,解决答案中提出的一些异议并提出一种解决方案供专家审查。

看评论,感觉不是大家没看懂核心问题,就是我没有突出核心问题。首先让我演示一下代码不会中断。以下代码允许 SalesEngineer 使用 sell() 和 buy() 功能访问 Abstraction,而 Driver 仅使用 start() 和 stop() 功能访问 Abstraction [以这种方式设计]。这是向不同客户端发布不同抽象的接口(interface)的最强特性。 Java 集合使用相同的多个基本类型,即 TreeSet 中的 ObjectComparable,一个用于 equals(),另一个用于实体上的 compare()。

package com.se.stackoverflow;

interface Vehicle {
    abstract void start();
    abstract void stop();
}

interface ShowroomItem {
    abstract void buy();
    abstract void sell();
}

class Car implements ShowroomItem, Vehicle {
    // **Car IS-A Vehicle and ShowroomItem BY-DEFINITION**
    // **and as per SOLID principle interface segregation**

    public void start() { System.out.println("Started");}
    public void stop() { System.out.println("Stopped");}
    public void sell() { System.out.println("Sold");}
    public void buy() { System.out.println("Baught");}
}

class SalesEngineer {
    private ShowroomItem item = null;
    public SalesEngineer(ShowroomItem item) { this.item = item;}
    public void doTransaction() {item.buy(); item.sell();}
}

class Driver {
    private Vehicle veh = null;
    public Driver(Vehicle veh) {this.veh = veh;}
    public boolean testDrive() {veh.start(); veh.stop(); return true;}
}

public class ShowroomOwner {
    public void makeDeal(Car carForDeal) {
        Driver driver = new Driver(carForDeal);
        SalesEngineer engineer = new SalesEngineer(carForDeal);
        if (driver.testDrive()) {
            engineer.doTransaction();
        }
    }

    public static void main(String[] args) {
        // simulates client as ShowroomOwner to save space
        new ShowroomOwner().makeDeal(new Car());
    }
}

在引用了 Jim Arlow 的“UML 2 and Unified Process”之后,我发现我们可以在序列图中通过生命线显示不断变化的状态。我觉得我们可以使用类似的符号来显示不断变化的类型对象 [我没有在 UML 的任何地方看到过这个记录,但这是我对 UML 组的建议]。

例如这里 myCar 是它的类 Car 的对象(对象的类永远不能改变)但它的引用类型根据左侧的不同而不同,如 ShowroomItem 或 Vehicle。

可能是下面的时序图可以显示出来。 [示例类只是指示性的,以突出显示自动类型转换效果]

enter image description here

最佳答案

UML 符号问题

您需要为时序图的每条生命线选择要显示的类型,因为 UML 只允许一个。由于 myCar 是一个 Car,它实现了 VehicleShowroomItem,您可以选择这 3 种类型中的任何一种。

一旦选择了类型,UML 就无法在同一图表中提供该类型的替代 View 。您可以显示 myCarCar 的场景。但是其他生命线必须符合他们所知道的接口(interface)(前提是没有其他使用依赖项使他们能够访问完整的 Car)并且由您来确保一致性。这可能容易出错,正如您使用 playMusic() 所演示的那样。

您可以通过图表中的一个或多个注释来解决您的问题,以纯文本形式提醒读者接口(interface)相关的约束。但更好的方法是保持简单并显示SalesEngineerCar 之间以及Driver 之间的交互和 Car 在两个单独的图中。这更接近您的设计的实际情况,并促进合理的关注点分离

OOP 设计问题

Qwerty_soBruno已经指出了您设计中的弱点。我完全同意他们的看法。实际上,Car 就是 Vehicle。但是 Car 不是 ShowroomItem:Car 可以暂时具有的作用> 陈列室元素。或者相反,陈列室元素可能在给定时间对应特定汽车。

如果汽车不是陈列室元素,它既不应该继承此类,也不应实现此类接口(interface)。因此,更喜欢 composition over inheritance ,例如:

  • SalesEngineer 交易 ShowroomItem
  • CarForSale 实现 ShowroomItem
  • CarForSale 关联到一辆 Car
  • Driver 驾驶着 Vehicle(注意:偏向滚动的车辆,因为飞机上没有司机 ;-) )
  • Car 实现了 Vehicle
  • Car 可以关联到 CarForSale(但前提是它由 SalesEngineer 出售)

这种设计确保了更好的关注点分离。例如,您可以仅sell()buy() 真正待售的汽车,而不是任何汽车。只有待售汽车才会有价格。

另一个优点是您可以在单个序列图中以更稳健的方式显示全貌,因为不同的职责由不同的对象实现

关于uml - 如何在 UML 对象和序列图中为同一对象分别显示引用类型和对象类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65772105/

相关文章:

uml - 在 Confluence 中自动更新 UML 图

class - 在UML类图中,如果B被类A使用的接口(interface)使用,我是否应该绘制从类A到B的依赖关系?

uml - 我如何避免类图中的循环关系

database - 数据库是序列图中的 Controller 还是边界?

python - 使用 python 或 perl 生成 uml 序列图

java - 程序的 UML 图(类图)

uml - 序列图中的发生与执行规范,何时使用?

uml - 任何在 native Win32 上运行的免费 UML 建模工具?

uml - Visual Paradigm 中代码和模型之间的同步

java - 我是否必须为序列图的每个类函数传递制定生命线?