в

Разница между абстрактным классом и интерфейсом

Для чего это всё

Допустим, вы работаете в команде над большим продуктом. В таких случаях удобно разделить одну большую программу на множество мелких подпрограмм и сервисов, каждый из которых решает свою узкую задачу.

Если заранее не договориться о том, как эти компоненты обмениваются данными между собой, то может случиться то, о чём мы уже предупреждали:

  • один программист делает функцию, которая отвечает за регистрацию новых пользователей;
  • все остальные используют эту функцию, привыкли к её параметрам и знают, что туда нужно передавать;
  • внезапно этот программист понимает, что можно запрограммировать более эффективный вариант регистрации, который будет работать гораздо быстрее;
  • он полностью переписывает функцию, и в этот момент у всей команды ломается логика программы: старые вызовы не работают, потому что функция теперь принимает другие данные (или в другой последовательности).

Чтобы такого не было, поступают так:

Один программист отвечает за регистрацию новых пользователей.
Он делает объект «Пользователь» и прописывает ему интерфейс «Зарегистрировать».
Также он говорит, что интерфейс «Зарегистрировать» будет принимать на вход три переменные: имя, почту и пароль.
Теперь программист говорит остальным: «Ребята, если нужно зарегистрировать нового пользователя — используйте интерфейс Пользователь.Зарегистрировать(имя,почта,пароль)».
Даже если внутри объекта поменяется вся логика работы, то это никак не повлияет на интерфейс — все так же смогут им пользоваться.
А всё потому, что никому нет дела, как тот программист реализовал свою часть, если через интерфейс всё работает нормально

Неважно, как он шифрует пароль, где хранит почту, как обрабатывает имя и в какую базу данных всё это складывает. Если интерфейс работает, все остальные могут продолжать разработку.

Текст

Михаил Полянин

Редактор

Максим Ильяхов

Художник

Даня Берковский

Корректор

Ирина Михеева

Вёрстка

Мария Дронова

Соцсети

Олег Вешкурцев

Где нужны интерфейсы

К примеру для реализации стандарта PSR-7 нужно реализовать интерфейсы:

Реализацию данных интерфейсов можно увидеть во многих фреймворках, например в slim:

  • ServerRequestInterface
  • ResponseInterface

Мы можем без проблем менять одну библиотеку на другую совместимую с PSR-7.

Интерфейс лучше добавлять тогда, когда он нужен.

Задача. Нужно преобразовать строку к нужным переводам строк в разных операционных системах.

Здесь может помочь интерфейс.

Теперь при добавлении другой операционной системой достаточно создать новый класс и реализовать там интерфейс

Для решения данной задачи лучше подойдет константа .

Когда нужно использовать интерфейс — это уже зависит от конкретной ситуации и понимание этого момента придёт с опытом и практикой.

When to use Abstract class Instead of Interface in C#?

This is one of the most frequently asked questions in C# dot-net interviews. Most developers are still not completely sure of the right answer. The following examples are used to illustrate these concepts.

  • The Abstract classes offer default functionality for the derived classes.
  • An abstract class is a great choice if you want to share a common code among several closely related classes. It acts as a base class and provides the common code implementation to the derived classes.
  • An abstract class can be used to achieve versioning of the components because by adding the new functionality to the base class all the derived classes will get updated automatically. An interface on the other hand can’t be modified once created and inherited by the classes. We must create a new interface if we want to add a new method to the interface.
  • You can go with the abstract class if you wanted to provide the default implementation to all the subclasses.
  • The Abstract class allows code reusability.
  • You can use an abstract class if we don’t want to implement all of the methods in a derived class but only some of them in a parent class.

Example 2: Abstract class in C#

Let’s create a simple program for an abstract class.

using System;

namespace AbstractClassDemo
{
    // Abstract class

    public abstract class Bank
    {
        // Abstract method
        public abstract void CashWithdraw(double amount);

        //field
        protected double balance;
        // Concrete method
        public void Balance()
        {
            Console.WriteLine($" Total Balance: {this.balance}");
        }
    }

    // Derived class "HsbcBank" inheriting base "Bank" class
    public class HsbcBank : Bank
    {
        // Constructor
        public HsbcBank(double amount)
        {
            this.balance = amount;
        }

        // Implementing base class method
        public override void CashWithdraw(double amount)
        {
            if (amount > this.balance)
            {
                Console.WriteLine(" Insufficient funds in bank account");
                return;
            }
            Console.WriteLine($" Withdrawing Cash ${amount} from HSBC Bank.");
            Console.WriteLine($" Remaining Balance : {this.balance - amount}");
        }
    }

    // Derived class "CityBank" inheriting base "Bank" class
    public class CityBank : Bank
    {
        // Constructor
        public CityBank(double amount)
        {
            this.balance = amount;
        }
        // Implementing base class method
        public override void CashWithdraw(double amount)
        {
            if (amount > this.balance)
            {
                Console.WriteLine(" Insufficient funds in bank account");
                return;
            }

            Console.WriteLine($" Withdrawing Cash ${amount} From City Bank.");
            Console.WriteLine($" Remaining Balance : {this.balance - amount}");
        }
    }

    class Program
    {
        static void Main()
        {
            Console.WriteLine("***** Abstract class example in C# *****");
            
            Bank bank = new HsbcBank(5000);
            bank.Balance();
            bank.CashWithdraw(300);

            Console.WriteLine();

            bank = new CityBank(10000);
            bank.Balance();
            bank.CashWithdraw(500);
           

            Console.ReadLine();
        }
    }   
}

The output of the above abstract class program.

Using the Code

Let me explain the code to make it a bit easier. There is an abstract class and an interface. Within the Abstract class and the Interface entity I am commenting on the differences between the artifacts.

I am testing both the Abstract class and the Interface by implementing objects from them. From the abstract class, we have inherited one object: . Similarly from we have inherited one object: .

In the test code under the GUI, I am creating instances of both and and then setting their attributes and finally calling the method of the objects.

Abstract Class Employee

using System;

namespace AbstractsANDInterfaces
{
    

    
    
    
    public abstract class Employee
    {
        


        

        protected String id;
        protected String lname;
        protected String fname;

        


        public abstract String ID
        {
            get;
            set;
        }

        public abstract String FirstName
        {
            get;
            set;
        }
        
        public abstract String LastName
        {
            get;
            set;
        }
        


        public String Update()
        {
            return "Employee " + id + " " + 
                      lname + " " + fname + 
                      " updated";
        }
        


        public String Add()
        {
            return "Employee " + id + " " + 
                      lname + " " + fname + 
                      " added";
        }
        


        public String Delete()
        {
            return "Employee " + id + " " + 
                      lname + " " + fname + 
                      " deleted";
        }
        


        public String Search()
        {
            return "Employee " + id + " " + 
                      lname + " " + fname + 
                      " found";
        }

        


        

        

        

        


        public abstract String CalculateWage();
        
    }
}

Interface Employee

using System;


namespace AbstractsANDInterfaces
{
    

    
    
    public interface IEmployee
    {
        


        
        
        
        


        

        

        

        


        String ID
        {
            get;
            set;
        }

        String FirstName
        {
            get;
            set;
        }
        
        String LastName
        {
            get;
            set;
        }
        
        


        

        

        


        String Update();

        String Add();

        String Delete();

        String Search();

        String CalculateWage();
    }
}

Inherited Objects

using System;

namespace AbstractsANDInterfaces
{
    

    
    
     
    

    public class Emp_Fulltime : Employee
    {
        


        

        


        public Emp_Fulltime()
        {
        }


        public override String ID
        {
            get

            {
                return id;
            }
            set
            {
                id = value;
            }
        }
        
        public override String FirstName
        {
            get

            {
                return fname;
            }
            set
            {
                fname = value;
            }
        }

        public override String LastName
        {
            get

            {
                return lname;
            }
            set
            {
                lname = value;
            }
        }

        

        

        public new String Add()
        {
            return base.Add();
        }
        


        

        public new String Delete()
        {
            return base.Delete();
        }
        


        

        public new String Search()
        {
            return base.Search();
        }
        


        

        public new String Update()
        {
            return base.Update();
        }
        
        


        

        

        public override String CalculateWage()
        {
            return "Full time employee " + 
                  base.fname + " is calculated " + 
                  "using the Abstract class...";
        }
    }
}
using System;

namespace AbstractsANDInterfaces
{
    
    

    
    
    

    public class Emp_fulltime2 : IEmployee
    {
        


        

        protected String id;
        protected String lname;
        protected String fname;

        public Emp_fulltime2()
        {
            


            

            

        }

        public String ID
        {
            get

            {
                return id;
            }
            set
            {
                id = value;
            }
        }
        
        public String FirstName
        {
            get
            {
                return fname;
            }
            set

            {
                fname = value;
            }
        }

        public String LastName
        {
            get
            {
                return lname;
            }
            set
            {
                lname = value;
            }
        }

        


        

        

        

        public String Add()
        {
            return "Fulltime Employee " + 
                          fname + " added.";
        }

        public String Delete()
        {
            return "Fulltime Employee " + 
                        fname + " deleted.";
        }

        public String Search()
        {
            return "Fulltime Employee " + 
                       fname + " searched.";
        }

        public String Update()
        {
            return "Fulltime Employee " + 
                        fname + " updated.";
        }
        
        


        

        

        

        public String CalculateWage()
        {
            return "Full time employee " + 
                  fname + " caluculated using " + 
                  "Interface.";
        }
    }
}




private void InterfaceExample_Click(object sender, 
                                System.EventArgs e)
{
    try

    {

        IEmployee emp;

        Emp_fulltime2 emp1 = new Emp_fulltime2();

        emp =  emp1;
        emp.ID = "2234";
        emp.FirstName= "Rahman" ;
        emp.LastName = "Mahmoodi" ;
        


        MessageBox.Show(emp.Add().ToString());
        
        

        MessageBox.Show(emp.CalculateWage().ToString());


    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

}

private void cmdAbstractExample_Click(object sender, 
                                   System.EventArgs e)
{

    Employee emp;

    emp = new Emp_Fulltime();
    

    emp.ID = "2244";
    emp.FirstName= "Maria" ;
    emp.LastName = "Robinlius" ;
    MessageBox.Show(emp.Add().ToString());

    


    MessageBox.Show(emp.CalculateWage().ToString());

}

Пример использования интерфейсов

Представьте, что у вас есть два класса, Microwave (микроволновая печь) и WashingMachine (стиральная машина), у которых есть только одна общая черта: им для работы требуется электричество. Что бы вы сделали, чтобы их соединить? Взгляните на приведенный ниже код, чтобы увидеть, как это можно сделать:

Лучший способ решить эту проблему – реализовать интерфейс, определяющий общее поведение. Именно это и делает Pluggable. Теперь каждый класс, расширяющий этот интерфейс, должен реализовывать все члены. При этом они могут подключаться к источнику питания.

В Java вы можете определять только постоянные свойства внутри интерфейсов. Итак, каждый раз, когда вы пытаетесь добавить свойство в Kotlin следующим образом:

Компилятор добавляет под капот public static final. В Java вам нужно инициализировать свойства, чтобы вы не могли делать что-то вроде этого:

Kotlin, с другой стороны, позволяет вам определять нестатические свойства внутри интерфейсов, которые могут быть только val. Это становится полезным, когда вы обрабатываете только одно значение, а метод слишком большой, как в свойстве neededWattToWork выше. Было бы неудобно определять метод только для возврата значения, хотя, как показывает декомпилированный код Java, компилятор в любом случае создает метод для свойства.

Однако Kotlin не позволяет создавать свойства var, потому что свойство var включает три компонента:

  • Поле private для хранения его значения.
  • getter, принимающий его значение.
  • setter для установки его значения.

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

What is Abstract class in C#?

An abstract class in C# is a class that cannot be directly instantiated using the keyword and always acts as a base class for other classes.

Abstract classes are created using the abstract keyword. They provide a common structure for derived classes to follow. The key characteristics of abstract classes in C# include:

  • Abstract classes in C# can contain abstract methods without actual code implementation. These methods must be implemented in the derived classes.
  • Abstract classes can also have non-abstract methods with actual code. Derived classes can inherit and, if needed, override these methods.
  • Unlike other classes, abstract classes in C# can’t be sealed. It means other classes can extend them further.
  • Abstract classes can have constructors, but you can’t create objects from them directly. Instead, objects of the abstract class are created using derived class constructors.

Here is an example of an abstract class in C#:

Output:

Code Explanation:

  • We define an abstract class with an abstract method that should be implemented by derived classes. It also has a non-abstract method with a default implementation.
  • We create a derived class that inherits from . It provides an implementation for the method.
  • In the method, we create an instance of the class, set its radius, and then call the method to calculate and display the area of the circle.

Теория¶

Пришло время разобраться в теории абстрактных классов, а именно ответить на вопросы, которые могут возникнуть при разработке программ.

Интерфейс или абстрактный класс — частый вопрос, ответ на который не всегда очевиден. В действительности, это абсолютно разные конструкции, как с точки зрения реализации, так и идеологии. Интерфейсы предназначены для описания публичного api, которое служит для сопряжения с программой. Кроме того, они не должны, а в TypeScript и не могут реализовывать бизнес-логику той части, которую представляют. Они — идеальные кандидаты для реализации слабой связанности (low coupling). При проектировании программ упор должен делаться именно на интерфейсы.

Абстрактные классы, при необходимости, должны реализовывать интерфейсы в той же степени и для тех же целей, что и обычные классы. Их однозначно нужно использовать в качестве базового типа тогда, когда множество логически связанных классов имеет общую для всех логику, использование которой в чистом виде не имеет смысла. Другими словами, если логика, размещенная в классе, не может или не должна выполняться отдельно от потомков, то необходимо запретить создание экземпляров подобных классов.

К примеру, абстрактный класс , реализующий интерфейс с двумя членами: свойством и методом , может и должен реализовать свойство , так как это свойство имеет заранее известное количество состояний (жив или мертв) и не может отличаться в зависимости от потомка. В то время как метод (подать голос) как раз таки будет иметь разную реализацию в зависимости от потомков, ведь коты мяукают, а вороны каркают.

Тем не менее, резонно может возникнуть вопрос, а почему бы не вынести этот функционал в обычный, базовый класс?

Абстрактный класс способен не только подсказать архитектору, что данная сущность является абстрактной для предметной области, то есть не является самостоятельной частью, но также не позволит создать экземпляр класса, работа которого может сломать приложение.

Еще раз то же самое, но другими словами. Поскольку базовый класс будет реализовывать логику, предполагаемую интерфейсами, разбитыми по принципу разделения интерфейсов, с помощью которых и будет происходить сопряжение с остальными частями программы, то существует возможность попадания его экземпляра в места, предполагающие логику, отсутствующую в нем. То есть высокоуровневая логика, присущая только потомкам, может быть сокрыта за менее специфичным интерфейсом, реализуемым самим базовым классом. Чтобы избежать подобных сценариев, допускающих возникновение ошибок во время выполнения, необходимо запретить создание экземпляров подобных классов. (Принцип разделения интерфейсов рассматривается в главе Interface)

Кроме того, абстрактный класс с помощью абстрактных членов не даст разработчику забыть реализовать необходимую логику в потомках.

Но и это ещё не все. Интерфейс в реальности будет составным типом. То есть, он будет принадлежать к типу , описывающему свойство и типу , описывающему метод . Реализовать подобное с помощью абстрактного класса не получится, так как класс может расширять только один другой класс, в то время как интерфейсы могут расширять множество других интерфейсов, и следовательно, принадлежать ко множеству типов данных одновременно. Как раз это и демонстрирует интерфейс , расширяя интерфейсы и .

Ещё часто можно встретить вопрос о замене интерфейсов абстрактными классами. Технически, абстрактный класс, состоящий только из абстрактных членов, может исполнять роль, идеологически отведенную интерфейсу. Но об этом лучше забыть, поскольку для описания открытой части объекта предназначен интерфейс.

Класс против интерфейса​

Во-первых, давайте посмотрим на различия между обычным конкретным классом и интерфейсом.

Класс — это определяемый пользователем тип, который действует как план создания объекта. Он может иметь свойства и методы, которые представляют состояния и поведение объекта соответственно.

Интерфейс также является определяемым пользователем типом, синтаксически похожим на класс. Он может иметь набор констант полей и сигнатур методов, которые будут переопределены классами реализации интерфейса.

В дополнение к этому, новые функции Java 8 поддерживают статические методы и методы по умолчанию в интерфейсах для поддержки обратной совместимости. Методы в интерфейсе неявно абстрактны, если они не являются или , и все они .

Однако, начиная с Java 9, мы также можем добавлять приватные методы в интерфейсы.

Абстрактный класс

концепция

В Java метод без тела метода должен быть определен как абстрактный метод, а если в классе есть абстрактный метод, класс должен быть определен как абстрактный класс.

Характеристики абстрактных классов

  • Необходимо использовать абстрактные классы и абстрактные методыАннотацияМодификация ключевого слова
  • Формат абстрактного класса:
  • Абстрактные классы не обязательно имеют абстрактные методы, классы с абстрактными методами должны быть абстрактными классами
  • Абстрактный класс не может быть создан, но в абстрактном классе может быть метод построения, цель которого – инициализировать, когда подкласс получает доступ к данным родительского класса.
  • Абстрактные классы не могут быть созданы напрямую, они создаются конкретными подклассами полиморфным способом.
  • Подкласс абстрактного класса

    • Либо абстрактный класс
    • Либо вы должны переопределить все абстрактные методы в абстрактном классе

Характеристики членов абстрактных классов

  • Переменная-член: переменная или постоянная
  • Метод построения: Да, используется для инициализации подкласса для доступа к данным родительского класса.
  • Метод члена: он может быть абстрактным или не абстрактным.

заметка

Характеристики методов-членов абстрактных классов:

  • Абстрактные методы заставляют подклассы делать что-то
  • Наследование подклассов неабстрактных методов, улучшение возможности повторного использования кода

Мышление

  • Если у класса нет абстрактных методов, можно ли его определить как абстрактный класс?

    Да, внешний мир не может создавать такие объекты, что равносильно методу строительства приватизированных классов.

  • С какими ключевыми словами не могут сосуществовать абстрактные ?

    • final: противоречивый, абстрактный обязательный подкласс должен быть переписан, final не позволяет переписывать подкласс
    • частные: противоречивые, абстрактные вынуждают переписывать подклассы, частные подклассы не могут быть унаследованы и не могут быть переписаны
    • static: статический метод принадлежит классу, поэтому в переписывании не участвует, бессмысленно

результат операции:

Интерфейс

Итак, у нас есть некое устройство с трубкой, микрофоном, динамиком и средством набора номера. Но если вы вспомните рассказы мамы, бабушки и подруги, то обнаружите вот что:

  • в микрофон говорят, чтобы собеседник мог вас услышать;
  • чтобы слышать самому, ухо прикладывают к динамику;
  • чтобы набрать номер, нужно с помощью номеронабирателя вызвать нужную последовательность цифр;
  • когда идёт вызов, слышны гудки в динамике.

Всё это — интерфейсы. Они позволяют работать с объектом, не вникая в то, как он устроен внутри. Если вы умеете работать с интерфейсом номеронабирателя, то вам всё равно, нужно ли крутить диск, нажимать физические кнопки на радиотрубке или давить пальцем на сенсорный экран. 

Такой интерфейс как бы говорит нам — я передам в телефон любые цифры, какие захочешь

Как я это сделаю внутри и как они будут обработаны — неважно, просто набери номер, а дальше телефон сам разберётся

Интерфейсы — это действия над объектом, доступные другим объектам (поэтому они называются публичными). 

Есть ещё инкапсулированные, то есть внутренние методы. Например, у микрофона есть публичный метод «Слушать голос», и есть внутренний метод «Преобразовать голос в электрические сигналы». С его помощью он взаимодействует с другими частями нашего абстрактного телефона. Про инкапсуляцию будет отдельный материал, потому что тема большая.

Сложная терминология

Строго говоря, интерфейсы — это не действия, а методы. Сейчас объясним. 

В программировании есть операции — это простейшие действия, например, скопировать значение из одной переменной в другую. 

Из простых действий составляются функции — это когда несколько операций «склеиваются» в нечто единое. Мы даём этой склейке название и получаем функцию. Например, может быть функция «проверить правильность электронного адреса», которая состоит из нескольких десятков простых операций. 

На языке ООП функции, привязанные к объектам, называются методами. Просто такой термин. По сути это функции, то есть склеенные вместе операции. 

Итого: метод — это набор простых действий, которые склеили в единое целое и засунули в объект. 

Понятие абстрактного класса

Абстрактные методы — это методы, которые объявлены в абстрактном классе, но не имеют тела. Они должны быть реализованы в классах-наследниках. Классы-наследники должны либо реализовать все абстрактные методы, либо быть также абстрактными.

Абстрактный класс может содержать и обычные (не абстрактные) методы с реализацией. Такие методы могут быть унаследованы и использованы в классах-наследниках без изменений или с дополнительной реализацией.

Особенности абстрактных классов:

  1. Нельзя создать объект абстрактного класса.
  2. Абстрактный класс может содержать конструкторы.
  3. Абстрактный класс может содержать переменные экземпляра и статические переменные.
  4. Абстрактный класс может быть наследован от другого абстрактного класса или реального класса.
  5. Абстрактный класс может реализовать интерфейс.

Интерфейс как тип данных

Давайте еще раз
внимательно посмотрим вот на эту строчку:

double s = ((MathGeom) gi).getSquare();

Как я только что
сказал, здесь происходит приведение типов от Geom к MathGeom. Но это значит,
что имя интерфейса можно воспринимать как тип данных? Это действительно так. В
частности, если добавить еще один интерфейс GeomInterface:

interface GeomInterface {
    double getCoords();
}

и применить его
ко всем трем классам графических примитивов:

class Line extends Geom implements GeomInterface {
    void draw() {
        System.out.println("Рисование линии");
    }
 
    public double getCoords() {
        return new double {1, 2, 3, 4};
    }
}
 
class Rectangle extends Geom implements MathGeom, GeomInterface {
    void draw() {
        System.out.println("Рисование прямоугольника");
    }
 
    public double getSquare() {
        return 5*10;
    }
 
    public double getCoords() {
        return new double {10, 20, 30, 40};
    }
}
 
class Triangle extends Geom implements MathGeom, GeomInterface {
    void draw() {
        System.out.println("Рисование треугольника");
    }
 
    public double getSquare() {
        return 0.5*4*10;
    }
 
    public double getCoords() {
        return new double {11, 12, 13, 14};
    }
}

То в функции main, мы можем
создать обобщенные ссылки типа GeomInterface:

        final int N = 3;
        GeomInterface g = new GeomInterfaceN;
        g = new Line();
        g1 = new Rectangle();
        g2 = new Triangle();

и через них
обращаться к методу getCoords:

        for(int i = ;i < N; ++i) {
            double coords = gi.getCoords();
 
            for(int j = ;j < coords.length; ++j)
                System.out.print(coordsj + " ");
 
            System.out.println();
        }

Разумеется,
ссылки g, g, g будут иметь
доступ только к методу getCoords, определенному в интерфейсе GeomInterface и ни к чему
более. Также этот пример показывает, что класс может применять сразу несколько
интерфейсов (в этом случае они записывают через запятую после ключевого слова implements). И тогда в нем
следует определять методы из обоих интерфейсов.

Путь кодера

Подвиг 1. Реализовать
интерфейс PersonInterface для единой
работы с БД сотрудников. В этом интерфейсе объявить абстрактные методы:

  • getInfo() – для
    получения общей информации о сотруднике;

  • getStatus() – для
    получения информации о должности;

  • getFIO() – для
    получения ФИО сотрудника.

Объявить
дочерние классы: Supervisers (для руководителей), Jobs (для рядовых
сотрудников), Clients (для клиентов).
В этих классах хранить информацию: ФИО, должность, год рождения, подразделение
(если есть), телефон, адрес. Реализовать интерфейс PersonInterface с определением
необходимых методов. Создать несколько экземпляров классов Supervisers, Jobs и Clients, используя
обобщенные ссылки типа PersonInterface. Вызвать для
этих объектов методы интерфейса и убедиться в их корректной работе.

Подвиг 2. Используя
интерфейс и классы из подвига 1, добавить к классам базовый класс Persons для хранения
общих полей: ФИО, год рождения, адрес. Кроме того, добавить две статические
переменные: count и count_clients для подсчета
числа сотрудников (классы Supervisers и Jobs) и клиентов
организации (класс Clients). Создать несколько объектов, используя
ссылки обобщенного типа PersonInterface. Вывести
информацию по объектам, а также число сотрудников и клиентов.

Видео по теме

#11 Концепция объектно-ориентированного программирования (ООП)

#12 Классы и создание объектов классов

#13 Конструкторы, ключевое слово this, инициализаторы

#14 Методы класса, сеттеры и геттеры, public, private, protected

#15 Пакеты, модификаторы конструкторов и классов

#16 Ключевые слова static и final

#17 Внутренние и вложенные классы

#18 Как делается наследование классов

#19 Ключевое слово super, оператор instanceof

#20 Модификаторы private и protected, переопределение методов, полиморфизм

#21 Абстрактные классы и методы

#22 Интерфейсы – объявление и применение

#23 Интерфейсы – приватные, статические и дефолтные методы, наследование интерфейсов

#24 Анонимные внутренние классы

#25 Перечисления (enum)

#26 Обобщения классов (Generics)

#27 Ограничения типов, метасимвольные аргументы, обобщенные методы и конструкторы

#28 Обобщенные интерфейсы, наследование обобщенных классов

Differences Between Abstract Classes and Interfaces in C#

Below are the key differences between abstract classes and interfaces in C#:

  • In C#, Abstract classes can provide both method implementations and declarations, Whereas Interfaces only contain method and property declarations without implementations.
  • Abstract classes can have constructors. At the same time, interfaces do not support constructors because they cannot be instantiated.
  • Abstract class members can have various access modifiers (public, protected, etc.), whereas Interface members are implicitly public and cannot have access modifiers.
  • In C#, an abstract class can have both fields and properties, while an interface supports properties but not fields, and they are implicitly abstract.
  • In C#, an abstract class is used to share and reuse common code among related classes. Meanwhile, an interface works more like a contract, ensuring that derived classes of unrelated types must implement the data members defined in the interface.
  • Abstract classes allow partial method implementation, whereas Interfaces require full method implementation in derived classes.
  • Abstract classes support single-class inheritance, while Interfaces allow multiple-interface inheritance.

Summary:

In this article, we learned about the ‘difference between the Abstract class and Interface in C#‘ with simple examples. Also, we learned the new features in an Interface introduced in C# 8.

I hope you found this post useful in learning about Abstract class and Interface in C#. Your comments, suggestions, and constructive criticism are much appreciated.

Recommended Articles:

  • C# Tutorial
  • Understanding Interface in C# with Examples
  • Understanding C# Abstract Class
  • SOLID Design Principles in C#: A Complete Example
  • Singleton Design Pattern in C#: A Beginner’s Guide with Examples
  • Top 50 C# Interview Questions and Answers For Freshers and Experienced in 2022
  • Collections in C#–Queue, Stack, ArrayList, and Hashtable
  • WCF vs Web API: Top 10 Differences Between WCF and Web API
  • C# Array vs List: When should you use an array or a List?
  • Generic Delegates in C# With Examples
  • Serialization and Deserialization in C# with Example
  • Sealed Class in C# with examples
  • C# Enum | How to Use enumeration type in C#?
  • Properties In C# with examples
  • Multithreading in C#
  • IEnumerable Interface in C# with examples
  • C# List Class With Examples
  • C# Struct vs Class
  • C# Dictionary with Examples

We would love to hear your thoughts on this post. Please leave a comment below and share it with others.

Общие характеристики¶

В TypeScript объявление абстрактного класса отличается от объявления обычного только добавлением ключевого слова перед ключевым словом .

1

Абстрактные классы так же, как и обычные классы, могут расширять другие обычные и абстрактные классы и реализовывать интерфейсы.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

Несмотря на то, что абстрактный класс — все же класс, главное его отличие от обычного класса заключается в отсутствии возможности создания его экземпляров. Другими словами, нельзя создать экземпляр абстрактного класса.

1
2
3
4
5
6

Абстрактные классы могут содержать абстрактные члены, принадлежность к которым указывается с помощью ключевого слова . Ключевое слово можно применить к полям, свойствам (аксессоры) и методам абстрактного класса. При этом свойства и методы не должны иметь реализацию. В отличие от них, полям, помеченным как абстрактные, может быть присвоено значение по умолчанию.

1
2
3
4
5
6
7

Абстрактный класс, расширяющий другой абстрактный класс, не обязан переопределять все абстрактные члены своего суперкласса. В отличие от абстрактных классов, обычные классы, расширяющие абстрактные классы, обязаны переопределить все поля, свойства и методы, находящиеся в иерархической цепочке и помеченные ключевым словом , если они не были реализованы предками ранее.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

Как было сказано ранее, абстрактным полям может быть задано значение по умолчанию, но в этом случае обратиться к нему могут только абстрактные классы в иерархии наследования.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

Абстрактные члены в полной мере удовлетворяют всем условиям реализации интерфейса. Другими словами, абстрактный класс, декларирующий реализацию интерфейса, может не реализовывать его члены, а лишь пометить их как абстрактные, тем самым переложить реализацию на своих потомков.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

Кроме абстрактных членов, абстрактные классы могут содержать обычные члены, обращение к которым ничем не отличается от членов, объявленных в обычных классах.

Как правило, абстрактные классы реализуют только ту логику, которая не будет ни при каких обстоятельствах противоречить логике своих подклассов.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22

Frequently asked questions

  • Why interfaces are better than abstract classes?It’s not necessarily accurate to say that interfaces are always better than abstract classes. Both interfaces and abstract classes have their unique use cases and advantages depending on the situation. Interfaces are useful when you want to define a contract for classes that implement them, provide a common interface for different implementations of the same behavior, and enable multiple inheritance. On the other hand, abstract classes are useful when you want to provide a base class for subclasses that share some common characteristics, provide default implementations of methods that can be overridden by subclasses, and define a template method.
  • Why abstract class is faster than interface in Java?It is not accurate to say that abstract class is faster than interface in Java, as both have different purposes and performance characteristics. The performance of a program that uses either interface or abstract class will depend on various factors, such as the design of the program, the complexity of the code, and the efficiency of the underlying hardware and software.
  • Why abstract classes Cannot be instantiated?Abstract classes cannot be instantiated because they are incomplete classes that have one or more abstract methods that are not implemented. An abstract method is a method without a body, which means it does not have a defined implementation. Because of this, it does not make sense to create an instance of an abstract class because there would be at least one method for which there is no implementation. Therefore, abstract classes can only be used as base classes for subclasses that provide concrete implementations for all the abstract methods.
  • Can an abstract class have a constructor?Yes, an abstract class can have a constructor in Java. The purpose of the constructor is to initialize the state of the abstract class, and it can be called by its subclasses using the super() keyword. However, since an abstract class cannot be instantiated on its own, the constructor is typically used to initialize the state of its subclasses.
  • Why is abstract class not 100% abstraction?An abstract class is not 100% abstraction because it can contain both abstract and non-abstract methods. Since an abstract class can have non-abstract methods, it is not completely abstract. However, the use of abstract classes allows for partial abstraction and can provide a useful structure for creating related classes with shared characteristics.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Шампиньон.

Различия бледной поганки и шампиньона