1

我有 2 个班级管理 2 个不同品牌的网络摄像头的运营,每个班级都有完全相同的公共成员,但私人成员却截然不同。其中一个或另一个停靠在 Pane 类中(哪种类型在运行时决定)。Pane 类提供额外的显示功能以及对停靠的任何相机的控制。当应用程序实例化 Pane 类并指定要停靠的相机类型时,我希望 Pane 实例化正确的相机类,以便它可以调用该类。

此示例代码的最后一行说明了我的问题...相机没有 .Start() 方法,因为相机的类型是 Object ,而不是两种 CameraType 类型之一。

如何让“对象相机”在设计时公开分配的类的成员,以便 Pane.Start() 最终调用在 switch/case 块中分配的类的 Start() 方法?

谢谢你的时间,戴夫

public class CameraType1  //not to be used directly
{
    public CameraType1()
    {
        Stuff specific to this type of camera
    }

    public void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class CameraType2  //not to be used directly
{
    public CameraType2()
    {
        // Stuff specific to this type of camera
    }

    public void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class Pane
{
    object camera;

    public Pane(string CameraTypeToDeploy)
    {
        switch (CameraTypeToDeploy)
        {
            case "Type1":
                camera = new CameraType1();
                break;
            case "Type2":
                camera = new CameraType2();
                break;
        }
    }

    public void Start()
    {
        camera.Start();   //wrong... camera doesn't have a Start() method
    }
}
4

3 回答 3

4

您需要一个通用的基本类型。您可以定义一个所有相机类型都实现的接口,或者您可以创建一个所有相机都继承的抽象基类型。或者你可以两者都做。针对接口进行编程并提供实现接口的基类并提供常用成员的实现。

public interface ICamera
{
    string Name { get; }
    void Start();
}

public abstract class CameraBase : ICamera
{
    public abstract void Start(); // Needs to be overridden in non abstract classes.
    public virtual string Name { get; protected set; } // May be overridden.
}

public class CameraType1 : CameraBase
{
    public CameraType1()
    {
        // Stuff specific to this type of camera
        Name = "Type 1";
    }

    public override void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class CameraType2 : CameraBase
{
    public CameraType2()
    {
        // Stuff specific to this type of camera
        Name = "Type 2";
    }

    public override void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class Pane
{
    ICamera camera;

    public Pane(string CameraTypeToDeploy)
    {
        switch (CameraTypeToDeploy) {
            case "Type1":
                camera = new CameraType1();
                break;
            case "Type2":
                camera = new CameraType2();
                break;
        }
    }

    public void Start()
    {
        camera.Start();   //OK, all cameras have a Start() method
    }
}

一个接口提供了很大的灵活性和高度的解耦;但是,它没有提供任何可以重用的实现。

没有接口的通用基类(抽象或非抽象)在类之间创建高度耦合,但可以为所有派生类提供现成的成员实现。

您可以结合两者的优点,如我的示例所示。如果相机应该与所有其他相机非常不同,您仍然可以决定让它直接实现接口,而不是从CameraBase. 当然,您还可以为不同的相似相机组(例如,来自同一公司的不同相机类型,具有相似的 API)提供多个相机基类。


更新#1

根据您的评论,您的相机类派生自供应商提供的基本类型。你仍然可以让他们实现一个接口。

public class VendorSpecificCamera
{
    public string Name { get; } 
    public bool VendorSpecificStart(int mode, int framesPerSecond)
}

public class CameraType1 : VendorSpecificCamera, ICamera
{
    // The 'Name' property is inherited from the vendor specific base class and
    // is therefore already implemented in this example.

    public bool CameraStarted { get; private set; }

    public void Start()
    {
        CameraStarted = VendorSpecificStart(2, 25);
    }
}

如果供应商类型已经具有与接口成员的签名匹配的成员,则您无需在派生类中执行任何操作。如果没有,只需提供缺少的成员。


更新#2

如果应密封供应商特定的相机类,则不能从中派生自己的类。然后,您将围绕供应商类创建一个包装类

public class CameraType1 : ICamera
{
    private VendorSpecificCamera _camera;

    public CameraType1()
    {
        _camera = new VendorSpecificCamera();
    }

    public string Name { get { return _camera.Name; } } 

    public bool CameraStarted { get; private set; }

    public void Start()
    {
        CameraStarted = _camera.VendorSpecificStart(2, 25);
    }
}

您还可以通过只读属性使供应商特定的相机可见,从而允许您访问供应商特定的属性。

public VendorSpecificCamera Camera { get { return _camera; } }
于 2012-12-10T20:17:15.353 回答
3

你让两者都实现一个接口ICamera

  public interface ICamera
  {
      void Start();
  } 

  public class Camera1 : ICamera 
  { 
       // your existing implementation 
  }

  public class Camera2 : ICamera 
  { 
       // your existing implementation 
  }

 public class Pane
 {
     ICamera camera;

     public Pane(string CameraTypeToDeploy)
     {
        // Your existing code
     }
     }

     public void Start()
     {
         camera.Start();   //ok, ICamera has a start method
     }
 }

接口是告诉程序几个类提供相同功能并且可以互换使用的最简单方法。另一种选择(抽象类或简单继承)往往会使一切变得更加混乱,但有时也是一种选择。

于 2012-12-10T20:09:38.763 回答
1

创建一个包含该.Start()方法的接口并同时拥有CameraType1CameraType2实现它。并具有该接口的属性cameraPane

public Interface CameraType
{
    void Start();
}

public class CameraType1 : ICameraType  //not to be used directly
{
    public CameraType1()
    {
        Stuff specific to this type of camera
    }

    public void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class CameraType2 : ICameraType  //not to be used directly
{
    public CameraType2()
    {
        // Stuff specific to this type of camera
    }

    public void Start()
    {
        // Stuff specific to starting a stream to this type
    }
}

public class Pane
{
    ICameraType camera;

    public Pane(string CameraTypeToDeploy)
    {
        switch (CameraTypeToDeploy)
        {
            case "Type1":
                camera = new CameraType1();
                break;
            case "Type2":
                camera = new CameraType2();
                break;
        }
    }

    public void Start()
    {
        camera.Start(); 
    }
}
于 2012-12-10T20:15:13.853 回答