如何实现许多具有相同方法的类来执行不同的操作?

时间:2011-04-29 04:33:29

标签: c# oop

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

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)
}

我不太确定,但我想我可以使用接口,也可以继承Device类的Device1类并覆盖方法......但我不知道怎么会有一个通用的方式说CurrentDevice.DoWork1(),因为CurrentDevice可能是Device1或Device2。

任何想法都将不胜感激。我在Windows XP SP3和Windows 7上使用Visual Studio 2008和.NET 3.5。

我希望我能够很好地描述这个问题。如果没有,或者如果我没有提到我应该提到的东西,请告诉我。我是stackoverflow和C#的新手。

谢谢,

迈克尔

4 个答案:

答案 0 :(得分:8)

在您的情况下,您基本上定义了一个继承层次结构,该层次结构可以包含抽象基类和两个派生类型,也可以包含两个实现者的接口。例如

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
 }

答案 1 :(得分:4)

起初我有点困惑,因为在这种情况下,电脑会进行计算,设备只会收到结果。据我所知,你需要在PC上不同的设备实现,而不是设备本身。

这里的真正诀窍不是使用接口或继承 - 你已经想到了这一点。诀窍是获得正确的实现类型,并为该部分使用工厂。

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

只有当“某些东西”真正成为一个普通但有意义的家庭的一部分时才使用继承。继承应该有一个非常强大的“是一个”元素。

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

我建议采用这种方法。

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

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

现在的诀窍是获得你需要的课程,而不必知道它是什么。要再次隐藏详细信息并使方法调用为通用,您可以创建参数化工厂。该工厂接受一个参数,该参数描述了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

    }

}

答案 2 :(得分:1)

您可能有兴趣为此查看一些设计模式。 http://www.oodesign.com/

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

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

答案 3 :(得分:0)

安东尼·佩格拉姆的回答非常好,但你可能想要更进一步。可以想象,虽然您的所有设备似乎都在执行相同的任务,但您可能会发现有些设备实际上并未执行所有任务,而其他设备执行的任务更多。

在这种情况下,您可能会尝试更改界面以添加另一个DoWork5DoWork6方法,并仅在没有特定行为的类型上引发NotImplemented个例外。

由于许多原因,这很麻烦。我建议(如果你发现自己处于这个位置)看看你的角色是否明确。您可以通过创建表示特定角色的接口(或一组行为---与接口隔离原则相关联)来实现此目的。

因此,IMediaPlayer PlayPauseRewind以及另一个IMediaRecorder采用Record方法可以{{1}}。通过这种方式,您可以在具体类上实现相关角色。

HTH