我有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
}
}
答案 0 :(得分: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; } }
答案 1 :(得分: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
}
}
接口是告诉程序多个类提供相同功能并且可以互换使用的最简单方法。另一个选项(抽象类或简单继承)往往会让一切变得更加混乱,但有时也是一种选择。
答案 2 :(得分:1)
创建一个包含.Start()
方法的接口,并让CameraType1
和CameraType2
实现它。并且camera
上的属性Pane
属于该界面。
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();
}
}