【问题标题】:How to Show Reference type and Object type separately for same object in UML object and sequence diagram如何在 UML 对象和序列图中分别显示同一对象的引用类型和对象类型
【发布时间】:2021-04-22 14:35:43
【问题描述】:

该图显示了示例类图以及序列图中这些类的对象的用法。

在上图中,myCar 实例可以通过ShowroomItem 的引用或接口Vehicle 的引用来引用。因此,客户 Driver/SalesEngineer 将获得功能访问权限。

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

但在序列图中,(为了清楚起见)我无法指出 DrivermyCar 的引用应该是 VehicleSalesEngineer 应该是 ShowroomItem

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

是否有任何符号可以显示这种细节?

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

查看 cmets,我觉得要么人们没有得到核心问题,要么我没有突出核心问题。首先让我演示代码不会中断。以下代码允许 SalesEngineer 使用 sell() 和 buy() 功能访问 Abstraction,而 Driver 可以仅使用 start() 和 stop() 功能访问 Abstraction [以这种方式设计]。这是向不同客户端发布不同抽象的接口的一个最强特性。 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 和统一流程”之后,我发现我们可以在序列图中显示生命线上不断变化的状态。我觉得我们可以使用类似的符号来显示不断变化的类型对象 [我没有在 UML 的任何地方看到这个记录,但它是我对 UML 组的建议]。

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

可能是下面的序列图可以显示它。 [示例类只是为了突出自动类型转换效果]

【问题讨论】:

  • PlayMusic 大写 P 确实是无处可去。但是playMusic绝对是基类的操作!概括也应该是实现。
  • 是的@qwerty_so 你是对的。关于实现。接受错误。我会尝试更正图表。但是 playMusic() (接受错字)我故意没有添加到基类中以表明它不能在基类 ref 上调用。这是一个演示代码来说明我的观点..
  • 编辑图片
  • 不过,playMusic 是合法的操作。困惑。
  • I feel either people did not get the core question, or I failed to highlight the core issue :考虑到所有三个我们“没有得到核心问题”显然问题来自您的问题。 This is a strongest feature of interfaces to publish different abstractions to different clients :这绝对是错误的,一个接口不知道“客户”也不关心他们,你混淆了接口和接口实现。 changing states over life line in sequence diagrams. :您在图表中使用的符号/概念不是标准的一部分,类型不是状态

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


【解决方案1】:

UML 符号问题

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

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

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

OOP 设计问题

Qwerty_soBruno 已经指出了您设计中的弱点。我完全同意他们的看法。事实上,Car 就是Vehicle。但是Car 不是ShowroomItemCar 可以暂时扮演陈列室物品的角色。或者反过来说,陈列室中的物品可能对应特定时间的特定汽车。

如果汽车不是陈列室物品,则它不应继承此类类,也不应实现此类接口。因此,更喜欢composition over inheritance,例如:

  • SalesEngineer 交易ShowroomItem
  • CarForSale 实现 ShowroomItem
  • CarForSale 与一个 Car 相关联
  • Driver 驾驶 Vehicle注意:偏向转向滚动车辆,因为飞机上没有司机 ;-)
  • Car 实现 Vehicle
  • Car 可以与CarForSale 关联(但仅限于由SalesEngineer 出售)

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

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

【讨论】:

    【解决方案2】:

    首先你的类图是错误的,汽车不是ShowRoomItem,汽车在航行/购买之前和之后是一样的,在你的情况下,汽车将不得不停下来(可能是暂时的) 成为 ShowRoomItem 因为它是航行/购买。事实上,它是一个陈列室项目,而不是一种类型,但在最好的情况下是一种状态,但对我来说,将这种状态作为汽车的一个属性也是错误的选择。

    司机或销售工程师访问的第二个实际实例是汽车,汽车不关心谁使用它,当这个人是销售工程师时收音机不会消失,所以汽车总是接受播放收音机如果足够前提条件已开启(电池有电,可能是钥匙开启等)

    根据人的身份有限制的事实不能在汽车的层面上完成,否则这是脱离现实并且完全人为的,而是在人/角色的层面上。

    在 UML 中,您可以使用 约束

    【讨论】:

    • 第五个元素中,根据驾驶员在启动汽车前必须插入的电子驾驶执照,汽车非常禁止使用这些功能;-)
    • @Christophe 但这仅适用于飞行汽车 :-))
    • 其实飞行汽车已经存在了。 Aeromobil 由一家斯洛伐克公司制造。我有机会从很近的距离看到一个(2017 年在一个展厅里)它证明未来已经是现在,但只是分布不均:m.youtube.com/watch?v=r7cN6Q2lqAw - 航空汽车还证明了什么:更喜欢组合而不是继承;- )
    • @Christophe 我的车你可以在我的个人资料中看到是一辆敞篷车,由阿斯顿马丁命名为 volante,在法语中 volante 的意思是 flying ...但幸运的是,即使在高速行驶时,它也可以留在地板上;-) 但他们在真正会飞的汽车上工作electronicdesign.com/markets/automotive/article/21806791/…
    【解决方案3】:

    由于Car (根据您的UML)从ShowRoomItem 继承,它还将具有sell() 操作并且SalesEngineer 可以使用它。

    我觉得你的模型很奇怪。具有sell() 操作的汽车绝对是我不会购买的。换句话说:你的类模型坏了。

    【讨论】:

    • 这个模型只是为了把我的等效 uml 的要点放在例如 If Vehicle v = new Car();那么 v.start() 和 v.stop() 应该只工作。 ShowroomItem 也是如此。我想知道如何显示对象是 Car 类型,但目前在 UML 对象图和序列图中被称为 Vehicle 类型。
    • 即使这是一个演示也应该是合理的。以上不是,至少对我而言。太难回答了。您可以按照 bruno 的建议进行约束。
    • 我不想写一个完整的答案,所以我只想补充一点,这表明需要“角色混合”。请参阅此提示:ontouml.readthedocs.io/en/latest/classes/nonsortals/rolemixin
    • @JimL。我猜 OntoUML 是一个特定的配置文件?
    • 这是一个在本体论上有充分根据的 UML 配置文件,有助于防止代价高昂的问题。
    猜你喜欢
    • 2013-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 2020-12-25
    • 2013-05-19
    • 1970-01-01
    • 2015-10-15
    相关资源
    最近更新 更多