如何实现许多具有相同方法但做不同事情的类呢?

本文关键字:方法 实现 许多具 何实现 | 更新日期: 2023-09-27 17:53:32

我是一名主要使用嵌入式设备(用C和汇编编程)的开发人员。我的c#和OOP知识非常有限(尽管我可以在必要的时候摸索一下)。我有5个设备通过USB接口与PC相连。PC机进行一些计算,并将结果发送给设备。对每个设备执行相同的计算,但计算方法不同。对于每个设备,我都有一个c# Windows Forms应用程序,它可以完成一些工作并向设备来回发送数据。目前,我正在尝试将五个不同的应用程序合并为一个,这样我们就可以轻松地进行更改,轻松地添加新设备,并拥有标准的用户界面。我的问题是,我不知道最好的方法,因为我不知道哪个设备将被使用,直到运行时。我试图避免一堆if语句,我希望能够把每个设备在一个单独的文件。下面是我所说的一些伪代码。

class Device //This is what EVERY device can do
{
...
DoWork1();
DoWork2();
DoWork3();
...
}
class Device1
{
...
DoWork1(); //This is how the work is done for this device
DoWork2();
DoWork3();
...
}
class Device2
{
...
DoWork1();  //This is how the work is done for this device (not the same way as   Device1)
DoWork2();
DoWork3();
}

public partial class frmMain : Form
{
private (some kind of object or something) CurrentDevice;
public frmMain()
{
...
//Determine what device (could be one of five) is currently being used
CurrentDevice = (which device is currently being used)
//Could be CurrentDevice = new Device1();
}
}
private void Button1_Click()
{
CurrentDevice.DoWork1(); //But this could be Device1.DoWork1() or Device2.DoWork1(), depending on what device is currently being used (which was determined in the frmMain constructor)
}

我不是很确定,但我想我可以使用一个接口,或者可能继承Device1类的设备类和覆盖的方法…但我不知道我将如何有一个通用的方式说CurrentDevice. dowork1(),因为CurrentDevice可以是Device1或Device2。

任何想法都将非常感激。我在Windows XP SP3和Windows 7上使用Visual Studio 2008和。net 3.5。

我希望我已经很好地描述了这个问题。如果没有,或者我没有提到我应该提到的事情,请让我知道。我是stackoverflow和c#的新手。

谢谢你,

Michael

如何实现许多具有相同方法但做不同事情的类呢?

在您的例子中,您基本上定义了一个继承层次结构,它可以由一个抽象基类和两个派生类型组成,也可以由一个接口和它的两个实现者组成。例如

public abstract class BaseDevice
{
    public abstract void DoWork1();
}
public class Device1 : BaseDevice
{
    public override void DoWork1()
    {
        // provide implementation here
    }
}
// also create Device2 : BaseDevice and implement 

或者你可以使用接口定义

public interface IDevice
{
    void DoWork1();
}
public class Device1 : IDevice
{
    public void DoWork1() 
    {
        // provide implementation 
    }
}

您选择哪种方法取决于您。例如,如果您希望定义在整个层次结构中常见的实现的某些行为或属性,那么您可能会倾向于使用抽象基类。使用抽象类,您可以提供实现。接口是一个空的契约,你不能提供任何通用的行为,只能定义可能存在的行为或属性。

无论采用哪种方式,都可以通过抽象或接口基类引用派生类型的实例。通过这种方式,您不关心实现类型是什么,只关心它能做什么(它的方法或属性)。

的例子:

 BaseDevice device1 = new Device1(); 
 BaseDevice device2 = new Device2();
 // maybe you have a list?
 List<BaseDevice> devices = new List<BaseDevice> { device1, device2 };
 foreach (BaseDevice device in devices)
 {
      device.DoWork1(); // notice you don't care about the actual type, just the behavior
 }

我一开始有点困惑,因为在这种情况下,pc确实计算,设备只接收结果。所以我的理解是,你需要在PC上实现不同的东西,而不是设备本身。

这里真正的技巧不是使用接口或继承——你已经知道了。关键是要获得正确的实现类型,这部分要使用工厂

但是你也必须决定继承还是接口。

只有当"某物"确实是一个共同的,但也有意义的家庭的一部分时,才使用继承。继承应该有很强的"是一个"元素。

OTOH可能存在许多可以进行计算的对象,但您可能不想创建一个家族。这就是组合有用的地方。要通过继承实现这一点,您需要让它们共享一个公共基类。在这里,您可以使用组合来允许每个对象使用公共接口来允许pc执行计算。

我建议这样做。

你应该有一个通用的,通用的接口,IDoCalculation,或类似的,定义一个方法签名,将以相同的方式调用任何设备的引用。

接下来,你必须获得该接口的设备特定实现,这是每个设备可以有不同实现的地方。为每个设备类型/实现创建一个类。

现在的技巧是得到你需要的类,而不必知道它是什么。要再次隐藏细节并使方法调用泛型,可以创建一个参数化的Factory。该工厂接受一个参数,该参数描述了pc需要为哪个设备进行计算。然后,它解释该参数,并在此基础上创建一个实现IDoCalculation的特定类。

我把它留给你去弄清楚这些对象需要如何组织成不同的程序集…

//Common interface
public interface IDoCalculation
{
    //Use whatever method signatures you need
    int DoCalculation();
}
public class DeviceImplementation1 : IDoCalculation
{

    #region IDoCalculation Members
    public int DoCalculation()
    {
        //Device 1 Specific code goes here
    }
    #endregion
}
public class DeviceImplementation2 : IDoCalculation
{

    #region IDoCalculation Members
    public int DoCalculation()
    {
        //Device 2 Specific code goes here
    }
    #endregion
}
// A simple factory that does not require a lot of OOP understanding.
public class DeviceCalculationFactory
{
    //Return a correct implementor based on the device type passed in
    public IDoCalculation GetCalculationImplementationInstance(string devicetype)
    {
        switch (devicetype)
        {
            case "Device1":
                return new DeviceImplementation1();
            case "Device2":
                return new DeviceImplementation2();
            default:
                //TODO ???
                return null;
        }
    }
}
// A simple client that calls the methods and then send the results
public class DeviceManager
{
    //To do the calculation, get an implementor for the correct device type from the factory - Presumably the PC knows the device of interest, example "Device1"
    public void DoTheCalculationThing(string deviceType)
    {

        DeviceCalculationFactory factory = new DeviceCalculationFactory();
        IDoCalculation calculation = factory.GetCalculationImplementationInstance(deviceType);
        int result = calculation.DoCalculation();
        // now send the result to the device
    }
}

您可能对这方面的一些设计模式感兴趣。http://www.oodesign.com/

特别是抽象工厂和模板方法。我想其中一个可能就是你要找的。http://www.oodesign.com/abstract-factory-pattern.html
http://www.oodesign.com/template-method-pattern.html

在我的理解中,您希望能够拥有一个基类,然后继承基类函数并在子类中定义它们。其中一种模式可能适合您的场景。

Anthony Pegram的回答很好,但是你可能想要更进一步。可以想象,尽管看起来你所有的设备都在执行相同的任务,但你可能会发现,实际上,有些设备并没有执行所有的任务,而另一些设备执行的任务甚至更多。

在这种情况下,您可能会试图更改接口以添加另一个DoWork5DoWork6方法,并简单地在没有特定行为的类型上引发NotImplemented异常。

这很麻烦,原因有很多。我建议(如果你发现自己处于这种境地)考虑一下明确你的角色。您可以通过创建表示特定角色(或一组行为——与接口分离原则联系在一起)的接口来实现这一点。

所以你可以有IMediaPlayerPlay, Pause, Rewind和另一个IMediaRecorderRecord方法。通过这种方式,您可以在具体类上实现相关角色。

HTH