Объясните утилиту абстрактных методов в C#

Просто 5-минутный обзор был бы хорош....

7
задан abatishchev 23 April 2011 в 08:19
поделиться

11 ответов

Просто посмотрите на Шаблон метода шаблона

9
ответ дан 6 December 2019 в 06:13
поделиться
public abstract class Request
{
   // each request has its own approval algorithm. Each has to implement this method
   public abstract void Approve();

   // refuse algorithm is common for all requests
   public void Refuse() { }

   // static helper
   public static void CheckDelete(string status) { }     

   // common property. Used as a comment for any operation against a request
   public string Description { get; set; }

   // hard-coded dictionary of css classes for server-side markup decoration
   public static IDictionary<string, string> CssStatusDictionary
}

public class RequestIn : Request
{
   public override void Approve() { }
}

public class RequestOut : Request
{
   public override void Approve() { }
}
7
ответ дан 6 December 2019 в 06:13
поделиться

Хорошим примером являются классы .NET Stream. Класс Stream включает базовую функциональность, которую реализуют все потоки, а затем конкретные потоки предоставляют конкретные реализации для фактического взаимодействия с вводом/выводом.

1
ответ дан 6 December 2019 в 06:13
поделиться

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

Предположим, у вас есть интерфейс с ... +20 методами, например, интерфейс List.

List {interface }
    + add( object: Object )
    + add( index:Int, object: Object )
    + contains( object: Object ): Bool
    + get( index : Int ): Object
    + size() : Int 
    ....

Если кому-то нужно предоставить реализацию для этого списка, он должен каждый раз реализовывать методы +20.

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

Например

Чтобы реализовать неизменяемый список, программисту нужно только расширить этот класс и предоставить реализации для методов get (int index) и size ()

AbstractList: List
    + get( index: Int ) : Object { abstract }
    + size() : Int { abstract }
    ... rest of the methods already implemented by abstract list

В этой ситуации: get и size - это абстрактные методы , которые разработчик должен реализовать. Остальной функционал может быть уже реализован.

EmptyList: AbstractList 
{
     public overrride Object Get( int index ) 
     {
          return this;
     }
     public override int Size() 
     {
          return 0;
     }
}

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

  List list = new EmptyList();

   foreach( Object o: in list ) {
   }

, чтобы избежать нулевых указателей.

1
ответ дан 6 December 2019 в 06:13
поделиться

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

0
ответ дан 6 December 2019 в 06:13
поделиться

Я не спец по C#. Не возражаете, если я использую Java? Принцип тот же. Я использовал эту концепцию в одной игре. Я рассчитываю значение брони у разных монстров по-разному. Полагаю, я мог бы заставить их отслеживать различные константы, но концептуально это гораздо проще.

abstract class Monster {
    int armorValue();
}

public class Goblin extends Monster {
    int armorValue() { 
        return this.level*10;
    }
}

public class Golem extends Monster {
    int armorValue() {
        return this.level*this.level*20 + enraged ? 100 : 50;
    }
}
0
ответ дан 6 December 2019 в 06:13
поделиться

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

public class ConnectionFactoryBase {

    // This is an actual implementation that's shared by subclasses,
    // which is why we don't want an interface
    public string ConnectionString { get; set; }

    // Subclasses will provide database-specific implementations,
    // but there's nothing the base class can provide
    public abstract IDbConnection GetConnection() {}

}

public class SqlConnectionFactory {
    public override IDbConnection GetConnection() {
        return new SqlConnection(this.ConnectionString);
    }
}
0
ответ дан 6 December 2019 в 06:13
поделиться
public abstract class MyBaseController {
    public void Authenticate() { var r = GetRepository(); }
    public abstract void GetRepository();
}
public class ApplicationSpecificController {
    public override void GetRepository() { /*get the specific repo here*/ }
}

Это просто какой-то фиктивный код, представляющий некоторый реальный код, который у меня есть (для краткости это просто пример кода)

У меня есть 2 приложения ASP MVC, которые делают довольно похожие вещи.Логика безопасности / сеанса (наряду с другими вещами) происходит одинаково в обоих. Я абстрагировал базовую функциональность из обеих в новую библиотеку, которую они оба наследуют. Когда базовому классу нужны вещи, которые могут быть получены только из фактической реализации, я реализую их как абстрактные методы. Поэтому в приведенном выше примере мне нужно извлечь информацию о пользователе из БД для выполнения аутентификации в базовой библиотеке. Чтобы получить правильную БД для приложения, у меня есть абстрактный метод GetRepository, который возвращает репозиторий для приложения. Отсюда база может вызвать какой-либо метод в репозитории, чтобы получить информацию о пользователе и продолжить проверку или что-то еще.

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

10
ответ дан 6 December 2019 в 06:13
поделиться

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

Взгляните на «реальный» пример со страницы doFactory Template Method Pattern .

1
ответ дан 6 December 2019 в 06:13
поделиться

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

public abstract class AbstractEntity<TId>
{
    public abstract TId Id { get; }

    public override void Equals(object other) 
    {
         if (ReferenceEquals(other,null)) 
             return false;
         if (other.GetType() != GetType() ) 
             return false;
         var otherEntity = (AbstractEntity<TId>)other;
         return Id.Equals(otherEntity.Id);
    } 
}
0
ответ дан 6 December 2019 в 06:13
поделиться

Пример

namespace My.Web.UI  
{  
    public abstract class CustomControl : CompositeControl  
    {
        // ...

        public abstract void Initialize();

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            // Anything custom

            this.Initialize();
        }
    }
}
0
ответ дан 6 December 2019 в 06:13
поделиться