在这种情况下,我应该/如何避免垂头丧气? [英] Should/how can I avoid downcasting in this case?

查看:140
本文介绍了在这种情况下,我应该/如何避免垂头丧气?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一个基类和派生类,其中派生类实现了一些其他特定于制造的功能:

Say I have a base and derived class, where the derived class implements some additional manufacture specific functionality:

class Device {
// Base class
}

class DeviceFromSpecificManufacture : public Device {
// Derived
}

我的程序运行时,它要求用户从一系列可用设备中选择一个设备.在这一点上,使用基类对我来说很好,因为我只需要基本的设备功能(与制造商无关)

When my program runs, it requires the user to select a device from an array of available devices. At this point, it's fine for me to use the base class as I only require basic device functionality (nothing specific to the manufacture):

std::vector<std::shared_ptr<Device>> availableDevices = getAvailableDevices();

// User selects device here, resulting in:
std::shared_ptr<Device> selectedDevice = ...

问题是:在某些时候,我只需要使用实现制造特定功能的类即可.

The problem is: at some point I'm going to need to only work with the classes that implement manufacture specific functionality.

执行此操作的一种方法是,在程序需要使用特定功能的时候,将我的基本实例转换为派生类型.

One way I can do this is by downcasting my base instance to the derived type, when the program is at a point where it needs to use the specific functionality.

std::shared_ptr<DeviceFromSpecificManufacture> specificDevice = std::dynamic_pointer_cast<DeviceFromSpecificManufacture>(selectedDevice);

// Here I would need to confirm that the cast was successful (as there's no guarantee 
// that selectedDevice is an instance of DeviceFromSpecificManufacture) - which 
// makes this feel even more wrong.

是否有更好的方法可以做到这一点?我无法将特定功能移至基类,因为它实际上并不适用于所有设备,仅适用于某些设备.

Is there a better way to do this? I cannot move the specific functionality to the base class, as it's really not applicable to all devices, just some.

推荐答案

垂头丧气几乎总是设计中矛盾的征兆.您的矛盾就在这里:

A downcast is almost always a symptom of a contradiction in the design. Your contradiction lies here:

[…]使用基类对我来说很好,因为我只需要基本的设备功能[…]

[…] it's fine for me to use the base class as I only require basic device functionality […]

[…]我将只需要使用实现制造特定功能的类.

[…] I'm going to need to only work with the classes that implement manufacture specific functionality.

显然,仅了解基类是不合适的,因为突然之间 事实证明您要做必须了解更具体的类型!?

Apparently it's not fine for you to only know about the base class because, suddenly, it turns out you do have to know about the more concrete type!?

通过使一段代码带有一个Device,您可以表达:这一段代码可与任何类型的Device一起使用.如果这段代码然后必须向下转换给出的Device并检查它是否真正可以处理的Device类型,那么我们必须问自己一个问题:如果这段代码实际上不能与任何类型的Device一起使用,为什么它接受任何类型的Device作为输入?如果将此代码赋予不能使用的Device,会发生什么情况?在实现过程中必须向下转换的组件会说一件事,然后再做另一件事……建议阅读: Liskov替代原则.

By having a piece of code take a Device, you express: This piece of code works with any kind of Device. If this piece of code has to then downcast the Device it was given and check whether it is of the kind of Device it actually can deal with, then we have to ask ourselves the question: If this piece of code cannot actually work with any kind of Device, why did it accept any kind of Device as input? What happens if this code is given a Device it can't work with? A component that has to downcast in its implementation says one thing and does another… recommended reading: Liskov substitution principle.

问题在于,哪种设计可以在您的特定应用程序中工作取决于特定的应用程序.在不了解该应用程序的情况下,很难提出一种修复设计的好方法.但是,这里有一些想法:

The problem is that what kind of design would work in your particular application depends on the particular application. Without knowing more about that application, it's very hard to suggest what would be a good way to fix the design. However, here are a few thoughts:

为什么将所有设备存储在同一集合中?为什么不将设备存储在单独的集合中,每种集合一个?这样一来,您不仅可以向用户显示设备,还可以按类别显示设备.这也意味着您不会丢弃所需的信息.

Why store all devices in the same collection? Why not store the devices in separate collections, one for each kind? That enables you to not just display the devices to the user, but display them by category. It also means you do not throw away the information you need.

或者,即使您不知道数据结构中所有对象的具体类型,对象本身也总是知道它们是什么.您可能会对双重分发模式(基本上是访客模式的一种版本)感兴趣.

Alternatively, even if you do not know the concrete types of all objects in your data structure, the objects themselves always know what they are. The Double Dispatch pattern (basically a version of the Visitor pattern) may be of interest to you.

最后,每当您看到std::shared_ptr时,都要问自己:这个对象确实有多个所有者吗?实际的共享所有权方案应该很少.就您而言,您似乎将设备存储在容器中.可能是,包含该容器的所有内容都是这些设备的唯一所有者.因此 std::unique_ptr 可能是一个更合适的选择……

Finally, whenever you see an std::shared_ptr, ask yourself: Does this object really have more than one owner? Actual shared ownership scenarios should be rather rare. In your case, you seem to be storing devices in a container. Chances are that whatever contains that container is the sole owner of these devices. Thus std::unique_ptr would probably be a more appropriate choice…

这篇关于在这种情况下,我应该/如何避免垂头丧气?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆