Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Liskov替换原理-公共接口_C#_Oop_Interface_Design Principles - Fatal编程技术网

C# Liskov替换原理-公共接口

C# Liskov替换原理-公共接口,c#,oop,interface,design-principles,C#,Oop,Interface,Design Principles,我一直在试图找出Liskov替换原则和接口分离原则,但我对下面的示例有点困惑 假设我们有一个名为Vehicle的基类,该基类具有两个属性和一个接口IVehile,该接口在IVehile类中实现 我们有两个儿童班,汽车和摩托车Car继承自Vehicle并实现IVehichile接口Motorcycle继承自Vehicle并实现了IVehicle,但是Motorcycle有一个额外的属性,该属性也添加到了在Motorcycle类中实现的新接口IMotorcycle中 让我用代码写下来澄清一下: pu

我一直在试图找出Liskov替换原则和接口分离原则,但我对下面的示例有点困惑

假设我们有一个名为
Vehicle
的基类,该基类具有两个属性和一个接口
IVehile
,该接口在
IVehile
类中实现

我们有两个儿童班,
汽车
摩托车
Car
继承自Vehicle并实现
IVehichile
接口
Motorcycle
继承自Vehicle并实现了
IVehicle
,但是
Motorcycle
有一个额外的属性,该属性也添加到了在
Motorcycle
类中实现的新接口
IMotorcycle

让我用代码写下来澄清一下:

public interface IVehicle
{
    string Brand { get; set; }
    string Model { get; set; }
    int HorsePower { get; set; }
}

public interface IMotorcycle
{
    DateTime DateCreated { get; set; }
}

public abstract class Vehicle : IVehicle
{
    public string Brand { get; set; }
    public string Model { get; set; }
    public int HorsePower { get; set; }
}

public class Car : Vehicle, IVehicle
{ }

public class Motorcycle : Vehicle, IVehicle, IMotorcycle
{
    public DateTime DateCreated { get; set; }
}

public class Start
{
    public IVehicle DoSomeStuff()
    {
        //Does some stuff
        //Based on logic we either return
        //a new Car or Motorcycle
        //but if I return a motorcycle how would I be able to 
        //access the DateCreated attribute since I'm returning IVehicle
        //I guess I have to cast it but is it a good practice to do that
        //or am I setting up everything incorrect?

        return new Motorcycle();
    }
}

我的问题:如果我们有一个类,比如说
Start
,它有一个返回
IVehicle
public-IVehicle-DoSomeStuff()
)的方法。根据逻辑,我们将返回一辆新的
汽车
摩托车
。如果我们返回一辆新的
汽车
,我们将能够访问所有属性,因为它只实现了
IVehille
接口,但假设我们返回一辆新的
摩托车
,我们如何能够访问
.DateCreated
属性而不强制转换它


有没有更好的方法来实现这一点,而不是有一个共同的交互,或者我遗漏了什么?

如果你想遵循LSP,如果你有一个接受IVehicle参数的方法,不管你是用汽车还是摩托车来调用它。如果您需要以任何方式强制转换或检查它是否是摩托车,则说明您没有正确设计接口。

如果您希望遵循LSP,如果您有一个接受IVehille参数的方法,则无论您是使用汽车还是摩托车调用它,都不应受到影响。如果您需要以任何方式铸造或检查它是否是摩托车,则说明您没有正确设计界面。

因此,本示例背后的一些想法非常突出
IMotorcycle
不是一个
IVehicle
,在本例中没有意义,因为假设没有一个类不会从
IMotorcycle
IVehicle
继承函数。因此,将
IMotorcycle
更改为从
iVihicle
继承将使事情更符合逻辑。接下来,您需要了解LSP和ISP的工作原理,并与其他可靠的原则一起工作。该实例不满足单响应和开闭原则

添加逻辑后,不应修改类
Start
。因此,如果您添加了一个实现了
IVehile
的新类和一些其他类/接口(它不是从
IVehile
继承的),则必须更改逻辑,这意味着它不能进行修改。
Start
类中应该有重写或重载的方法,以便您可以使用方法转发来处理不同的类型

但也有一个问题,那就是单一责任不适用于班级。如果您希望处理与车辆的一般交互,则应传入扩展
IVehille
的对象,但如果您正在创建/构建
IVehille
的实例,则应应用factory/builder模式。无论是哪种方式,
Start
类都应该创建、管理或与
IVehile
对象交互,而不是创建、管理和与对象交互。调用
Start
类的任何函数都应该实现SOLID,这意味着它只需要一个
IMotorcycle
IVehicle
对象(其中
IMotorcycle
继承自
IVehicle
),这样该函数就具有单个功能,添加更多类后不需要更新

还有更多,但我觉得我已经提供了很多信息。你应该考虑的主要问题是,你需要让坚实的原则一起工作,而不是孤立地工作。如果要在从返回更高级别接口的方法获取某个对象后使用该对象的特定于类型的函数,则需要使更高级别接口具有在实现时将调用特定于类型的函数的函数。在您的情况下,您可以有如下内容:

public interface IVehicle
{
    string Brand { get; set; }
    string Model { get; set; }
    int HorsePower { get; set; }
    void setInformation;
    InformObject getInformation;

}

public interface IMotorcycle : IVehicle
{
    DateTime DateCreated { get; set; }
}

public abstract class Vehicle : IVehicle
{
    public string Brand { get; set; }
    public string Model { get; set; }
    public int HorsePower { get; set; }
    public void setInformation(string brand, string model, int hPower){
       Brand = brand;
       Model = model;
       HorsePower = hPower;
    }
    public InfoObject getInformation(){
       return new InfoObject(Brand, Model, HorsePower);
    }

}

public class Car : Vehicle, IVehicle
{ }

public class Motorcycle : Vehicle, IVehicle, IMotorcycle
{
    public DateTime DateCreated { get; set; }
}

public class InfoObject 
{
    public InfoObject(string brand, string model, int hPower){
       Brand = brand;
       Model = model;
       HorsePower = hPower;
    }

    public InfoObject(string brand, string model, int hPower, DateTime timeCreated){
       Brand = brand;
       Model = model;
       HorsePower = hPower;
       DateCreated = timeCreated;
    }

    public string Brand { get; set; }
    public string Model { get; set; }
    public int HorsePower { get; set; }
    DateTime DateCreated { get; set; }
}

然后,您就可以将该信息作为一个需要有限信息量的对象。这不应反映层次结构
IVehicle
。它只是一个所有车辆都应该拥有的对象,所有车辆都可以与之交互,其他特定于类型的代码可以与之交互,以处理特定于该类型的信息。这不是一个很好的例子,只是作为一个整体来看待如何改进界面,因为如果您计划在整个系统中使用
IVehicle
,则需要做更多的工作来突出功能。Getter和setter并不是为其创建接口的最佳方法

下面是一些与本示例背后的想法相一致的东西
IMotorcycle
不是一个
IVehicle
,在本例中没有意义,因为假设没有一个类不会从
IMotorcycle
IVehicle
继承函数。因此,将
IMotorcycle
更改为从
iVihicle
继承将使事情更符合逻辑。接下来,您需要了解LSP和ISP的工作原理,并与其他可靠的原则一起工作。该实例不满足单响应和开闭原则

添加逻辑后,不应修改类
Start
。因此,如果您添加了一个实现了
IVehice
和som的新类