Принцип подстановки Лискова - общий интерфейс - PullRequest
0 голосов
/ 25 апреля 2018

Я пытался выяснить принцип подстановки Лискова и принцип сегрегации интерфейса, и меня немного смущает следующий пример.

Предположим, что у нас есть базовый класс Vehicle с парой свойств и интерфейсом IVehicle, который реализован в классе IVehicle.

У нас есть два дочерних класса, Car & Motorcycle.Car наследуется от Vehicle и реализует интерфейс IVehicle.Motorcycle наследуется от Vehicle и также реализует IVehicle, но Motorcycle имеет дополнительное свойство, которое также добавлено в новый интерфейс IMotorcycle, реализованный в классе Motorcycle.

Позвольте мне уточнить это, записав это в коде:

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()).Основываясь на логике, мы либо вернем новый Car, либо Motorcycle.Если мы вернем новый Car, мы сможем получить доступ ко всем свойствам, поскольку он реализует только интерфейс IVehicle, но давайте предположим, что мы вернем новый Motorcycle, как мы сможем получить доступ к свойству .DateCreated без приведенияэто,

Есть ли способ реализовать это лучше, чтобы вместо этого иметь общее взаимодействие или я что-то пропустил?

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Итак, несколько вещей, которые выделяются идеей этого примера.IMotorcycle не является IVehicle, что не имеет смысла в этом примере, поскольку предполагается, что не было бы класса, который бы не наследовал функции от IMotorcycle и IVehicle.Поэтому изменение IMotorcycle для наследования от IVehicle сделает вещи более логичными.Затем вам нужно понять, что LSP и ISP работают с другими принципами SOLID для работы.Пример не удовлетворяет принципу единственной ответственности и открытого закрытого типа.

Класс Start не следует изменять после добавления логики.Таким образом, если вы добавили новый класс, который реализовал IVehicle, и какой-то другой класс / интерфейс (который не наследуется от IVehicle), то логику пришлось бы изменить, то есть она не закрыта для изменений.В классе Start должны быть переопределенные или перегруженные методы, чтобы можно было использовать переадресацию методов для обработки различных типов.

Но есть и проблема единой ответственности, которая не распространяется на класс.Если вы хотите обрабатывать общие взаимодействия с транспортными средствами, следует передать объект, который расширяет IVehicle, но если вы создаете / строите экземпляр IVehicle, то должен применяться шаблон фабрики / строителя.В любом случае класс Start должен создавать, управлять или взаимодействовать с объектами IVehicle, не создавая, не управляя и не взаимодействуя с объектами.Независимо от того, какая функция вызывается в классе Start, она также должна реализовывать SOLID, что означает, что она ожидает только объект IMotorcycle или IVehicleIMotorcycle наследованием от IVehicle.) Таким образом, функция имеет единственную функциональность, делаетне нужно обновлять после добавления новых классов.

Это еще не все, но я чувствую, что уже дал много информации.Главное, о чем вы должны подумать, - это чтобы принципы SOLID работали вместе, а не изолированно.Если вы хотите использовать функции, специфичные для типа, из одного объекта после получения его от метода, который возвращает интерфейс более высокого уровня, вам нужно сделать так, чтобы интерфейс более высокого уровня имел функции, которые при реализации будут вызывать функции, специфичные для типа.В вашем случае у вас может быть что-то вроде этого:

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 во всей вашей системе.Геттер и сеттеры - не лучшая идея для создания интерфейса.

0 голосов
/ 25 апреля 2018

Если вы хотите следовать LSP, если у вас есть метод, который принимает параметр IVehicle, не должно иметь значения, вызываете ли вы его с автомобилем или мотоциклом.если вам нужно разыграть или проверить, является ли это мотоцикл каким-либо образом, вы неправильно разработали свой интерфейс (ы).

...