【问题标题】:How would one implement many classes that have the same methods that do things different?如何实现许多具有相同方法但做不同事情的类?
【发布时间】:2011-04-29 04:33:28
【问题描述】:

我是一名主要使用嵌入式设备(使用 C 和汇编进行编程)的开发人员。我的 C# 和 OOP 知识非常有限(尽管我可以在必要时假装通过它)。我有五个通过 USB 与 PC 连接的设备。 PC 进行一些计算并将结果发送到设备。对每个设备执行相同的计算,但计算方式不同。对于每台设备,我都有一个 C# Windows 窗体应用程序,该应用程序执行一些工作并将数据来回发送到设备。目前,我正在尝试将五个不同的应用程序合并为一个,以便我们可以轻松地进行更改、轻松地添加新设备并拥有标准的用户界面。我的问题是我不完全知道最好的方法,因为直到运行时我才知道将使用哪个设备。我试图避免一堆 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 类的 Device 类并覆盖这些方法...但我不知道如何使用一种通用方式说 CurrentDevice.DoWork1() 因为 CurrentDevice 可能是 Device1 或 Device2。

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

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

谢谢,

迈克尔

【问题讨论】:

  • 感谢大家的帮助和建议。我决定使用 Sisyphus 提供的解决方案,因为它非常适合我当前的应用程序。不过,每个人都对此提出了很好的意见,我感谢大家。 :)

标签: c# oop


【解决方案1】:

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

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
 }

【讨论】:

    【解决方案2】:

    起初我有点困惑,因为在这种情况下,电脑进行计算,设备只接收结果。因此,据我了解,您需要在 PC 上对某些东西进行不同的实现,而不是设备本身。

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

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

    仅当“某物”确实属于一个共同但又有意义的家庭时,才使用继承。继承应该有一个非常强烈的“是”元素。

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

    【讨论】:

      【解决方案3】:

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

      特别是抽象工厂和模板方法。我认为其中之一可能是您正在寻找的。 http://www.oodesign.com/abstract-factory-pattern.html
      http://www.oodesign.com/template-method-pattern.html

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

      【讨论】:

      • +1 用于建议模板方法。这就是要走的路。 @Anthony,您可以在抽象基类中使用默认实现,而衍生类只能覆盖特定方法。
      【解决方案4】:

      Anthony Pegram 的回答非常好,但您可能想更进一步。可以想象,尽管您的所有设备似乎都在执行相同的任务,但您可能会发现有些设备实际上并没有执行所有任务,而其他设备执行的更多。

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

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

      因此,您可以使用 PlayPauseRewind 和另一个带有 Record 方法的 IMediaRecorder。通过这种方式,您可以在具体类上实现相关角色。

      HTH

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-09
        • 1970-01-01
        • 1970-01-01
        • 2022-01-27
        相关资源
        最近更新 更多