Jak wybrać pomiędzy interfejsem a klasą bazową dla nowej implementacji?

Jeśli chodzi o implementację, jak wybrać typ bazowy lub interfejs ? Starałem się wypracować na kilku przykładach, ale nie rozumiem całego pomysłu: (

Przykłady jak i dlaczego byłyby bardzo mile widziane..

Author: Dan, 2013-03-23

6 answers

Klasa bazowa, abstrakcyjna lub nie, może zawierać zaimplementowane elementy. Interfejs nie może. Jeśli wszystkie implementacje będą działać podobnie, klasa bazowa może być dobrym rozwiązaniem, ponieważ wszystkie klasy potomne mogą współdzielić te same implementacje członków klasy bazowej. Jeśli nie będą współdzielić implementacji, wtedy interfejs może być drogą do zrobienia.

Przykład:

class Person
{
    string Name { get; set; }
}

class Employee : Person
{
    string Company { get; set; }
}

To ma sens dla pracownika dziedziczyć po osobie, ponieważ pracownik klasa nie musi definiować właściwości Name, ponieważ dzieli implementację.

interface IPolygon
{
    double CalculateArea()
}

class Rectangle : IPolygon
{
    double Width { get; set; }
    double Height { get; set; }

    double CalculateArea()
    {
        return this.Width * this.Height;
    }
}

class Triangle : IPolygon
{
    double Base { get; set; }
    double Height { get; set; }

    double CalculateArea()
    {
        return 0.5 * this.Base * this.Height;
    }
}

Ponieważ Rectangle i Triangle mają tak różne implementacje CalculateArea, dziedziczenie z klasy bazowej nie ma sensu.

Jeśli tworzysz klasę bazową i stwierdzisz, że w tylko zawiera elementy abstrakcyjne, równie dobrze możesz użyć interfejsu.

I, jak stwierdza j_ _ m, nie można dziedziczyć z wielu klas bazowych, ale można zaimplementować wiele interfejsy.

Zazwyczaj definiuję interfejsy jako pierwsze, a jeśli znajdę duplikację kodu w moich implementacjach, stworzę klasę bazową, która implementuje interfejs i sprawi, że moje implementacje odziedziczą po nim.

 39
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-23 06:42:20

Aby zdecydować, czy użyć klasy abstrakcyjnej, czy interfejsu, uważam ten artykuł za bardzo pomocny Source:

Dobrym sposobem na rozróżnienie przypadku dla jednej lub drugiej dla mnie zawsze było następujące:

  1. Czy istnieje wiele klas, które można "pogrupować" i opisać jednym rzeczownikiem ? Jeśli tak, należy utworzyć klasę abstrakcyjną o nazwie tego rzeczownika i dziedziczyć od niej klasy. (Kluczowym decydentem jest to, że klasy te dzielą funkcjonalność, a ty nigdy nie stworzysz tylko zwierzęcia... zawsze tworzysz pewien rodzaj Animal: implementację Twojej Animal klasy bazowej) przykład: Kot i pies mogą dziedziczyć po klasie abstrakcyjnej zwierzę , a ta abstrakcyjna klasa bazowa zaimplementuje metodę Void Breathe(), którą wszystkie zwierzęta będą zatem robić w dokładnie taki sam sposób. (Mogę uczynić tę metodę wirtualną, aby Mogę go zastąpić dla niektórych zwierząt, takich jak ryby, które nie oddychają tak samo jak większość zwierząt).

  2. Jakie rodzaje czasowników mogą być stosowane do mojej klasy, które ogólnie mogą być stosowane również do innych? Utwórz interfejs dla każdego z tych czasowników. przykład : wszystkie zwierzęta mogą być karmione, więc stworzę interfejs o nazwie IFeedable i każę Animal to zaimplementować. Tylko pies i koń są wystarczająco ładne, aby wdrożyć ILikeable - nie zaimplementuję tego na klasie bazowej, ponieważ nie dotyczy to Cat.

Proszę również spojrzeć na to Interface vs Base class pytanie.

 17
Author: Alina B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:56

Jednym z powodów, dla których należy używać klas abstrakcyjnych, jest wymuszenie inicjalizacji (np. Stanów za pomocą konstruktora).

Interfejs nie pozwala definiować kontraktów konstruktora.

W poniższym przykładzie każdy obiekt zwierzęcy powinien mieć nazwę. Nie można tego wymusić za pomocą interfejsu.

public abstract class Animal
{
    public Animal(string name)
    {
        this.Name = name;
    }

    public string Name 
    { 
        get; 
        private set; 
    }
}

public class Cat : Animal
{
    public Cat(string name)
        : base(name)
    {

    }

    string NoOfLegs { get; set; }
}



class Program
{
    static void Main(string[] args)
    {
        Animal aCat = new Cat("a");
    }
}
 4
Author: jacob aloysious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-23 10:20:14

Właściwie nie muszą się wzajemnie wykluczać. Możesz użyć obu w zależności od tego, jak ewoluuje twoja implementacja kodu.

Interfejs jest zwykle wypowiedzeniem umowy. Określa oczekiwane zachowanie, które realizatorzy powinni honorować. I zwykle uważa się za dobrą praktykę kodowanie publicznego api przeciwko interfejsom. W ten sposób redukujesz sprzężenie do szczegółów wdrożeń i pozwalasz na łatwiejszą refaktoryzację i konserwację kod. Teraz to, co kwalifikuje się jako publiczne api, to komponenty oprogramowania, które ucieleśniają interakcję wysokiego poziomu zdefiniowaną w Twoim projekcie i są przeznaczone do wielokrotnego użytku zarówno przez Ciebie, jak i innych w ramach tego samego projektu lub kilku projektów o niezależnym zakresie.

Klasa bazowa jest już częścią implementacji . Niezależnie od tego, czy implementuje interfejs, czy nie. I wiąże swoją potencjalną hierarchię z konkretnymi szczegółami implementacji: stan obiektu, overridable lub non metody nadmiarowe itp.

 3
Author: ylabidi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-23 06:37:09

Interfejsy są bardziej elastyczną konstrukcją. Możesz mieć tylko jedną klasę bazową, ale możesz zaimplementować wiele interfejsów. Jeśli potrzebujesz obiektu do obsługi wielu zachowań, ale więcej niż jedno z nich wymaga określonej klasy bazowej, nie będziesz w stanie tego zrobić.

Jak zauważa Dan, klasy bazowe mają przewagę wygody w wielu językach, ponieważ można zapewnić implementację bazową. Aby to zrobić z interfejsem wymaga utworzenia klasy, która zapewnia bazę implementacji, a następnie ręcznie delegować implementację każdej metody interfejsu do tej klasy-nie tak wygodne.

 2
Author: j__m,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-23 06:22:06

Znajduję tutaj analogię:

Abstract Base Class: - Producent samochodów może opracować silnik benzynowy, który ma kilka wariantów (1.6, 2L itp.). Odlewanie bloku silnika można uznać za abstrakcyjną klasę bazową , tzn. definiuje ona podstawowy kształt i cechy silnika. Wersja 2L może mieć większą głowicę cylindra itp.

Interfejsy: - Silnik może również korzystać z różnych części zamiennych, np. alternatora, chłodnicy, rozrusznika itp. oraz musi więc zaimplementować interfejsy zdefiniowane przez te komponenty. Komponenty te były zazwyczaj projektowane bez znajomości silników, które mogą ich używać.

 1
Author: Adrian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 11:25:55