2010-05-20 7 views

Antwort

7
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() { } 
} 
+0

Warum machst du das als abstrakte Methode und nicht als Schnittstelle? Ist es nur leichter, wenn Sie nur ein paar Dinge implementieren Request implementieren? –

+6

Wie ist das ein reales Beispiel? – Oded

+2

Eine abstrakte Klasse kann Methoden implementieren, so dass Sie dort möglicherweise ein Standardverhalten haben, nach dem ein Nachkomme anruft ... Sie können dies nicht mit einer Schnittstelle tun. –

0

für eine hausgemachte Version von Tetris Verwendet es, wo jeder Typ Tetraminos eine Klasse Kind war von die Tetramino-Klasse.

0

Sie könnten eine abstrakte Methode verwenden (anstelle einer Schnittstelle) jedes Mal, wenn Sie eine Basisklasse haben, die tatsächlich einige Implementierungscode enthält, aber es gibt keine vernünftige Default-Implementierung für eine oder mehrere seiner Methoden:

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

Angenommen, Sie haben einige Klassen, die den Zeilen in Ihrer Datenbank entsprechen. Vielleicht möchten Sie, dass diese Klassen als gleich gelten, wenn ihre ID gleich ist, denn so funktioniert die Datenbank. Sie könnten also die ID abstrahieren, weil Sie damit Code schreiben könnten, der die ID verwendet, aber nicht implementieren, bevor Sie die ID in den konkreten Klassen kennen. Auf diese Weise vermeiden Sie die Implementierung der gleichen equals -Methode in allen Entitätsklassen.

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

Ich bin kein C# Typ. Darf ich Java benutzen? Das Prinzip ist das gleiche. Ich habe dieses Konzept in einem Spiel verwendet. Ich berechne den Rüstungswert verschiedener Monster sehr unterschiedlich. Ich nehme an, ich könnte sie verschiedene Konstanten verfolgen lassen, aber das ist konzeptionell viel einfacher.

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; 
    } 
} 
+1

Wie beschrieben, bietet Ihr Beispiel eine Begründung für die Verwendung einer Schnittstelle, aber keine Rechtfertigung für die Verwendung einer abstrakten Klasse. – Brian

+0

Ich denke, ich hätte 20 weitere Zeilen Code einfügen können, um es ausführlicher zu machen. Ich sehe auch, wie ich ein Interface wie Attackable hätte verwenden können, das (unter anderem) armorValue() als Mitglied hätte. Ich denke aber immer noch, dass dies den Punkt recht gut illustriert: Sowohl Goblins als auch Golems haben einen Rüstungswert, aber sie müssen anders berechnet werden. – corsiKa

1

Verwendung der abstrakten Methode ist sehr üblich, wenn Sie die Template Method Pattern verwenden. Sie können damit das Skelett eines Algorithmus definieren und Unterklassen bestimmte Schritte des Algorithmus modifizieren oder verfeinern, ohne seine Struktur zu ändern.

Werfen Sie einen Blick auf ein "real-world" Beispiel von doFactory's Template Method Pattern page.

10
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*/ } 
} 

Dies ist nur einige Dummy-Code, der einige realen Welt Code repräsentiert ich haben (der Kürze halber dies nur Beispielcode ist)

Ich habe 2 ASP MVC-Anwendungen, die ziemlich ähnliche Dinge zu tun. Sicherheit/Sitzung Logik (zusammen mit anderen Dingen) passiert das gleiche in beiden. Ich habe die Basisfunktionalität von beiden in eine neue Bibliothek abstrahiert, die beide erben. Wenn die Basisklasse Dinge benötigt, die nur aus der eigentlichen Implementierung erhalten werden können, implementiere ich diese als abstrakte Methoden. In meinem obigen Beispiel muss ich Benutzerinformationen aus einer Datenbank abrufen, um die Authentifizierung in der Basisbibliothek durchzuführen. Um die richtige DB für die Anwendung zu erhalten, habe ich eine abstrakte GetRepository Methode, die das Repository für die Anwendung zurückgibt. Von hier aus kann die Basis eine Methode auf dem Repo aufrufen, um Benutzerinformationen zu erhalten und mit der Validierung fortzufahren, oder was auch immer.

Wenn eine Änderung an der Authentifizierung vorgenommen werden muss, muss ich jetzt nur eine Lib aktualisieren, anstatt doppelte Anstrengungen in beiden zu machen. Kurz gesagt, wenn Sie einige Funktionen implementieren möchten, aber nicht alle, dann funktioniert eine abstrakte Klasse großartig. Wenn Sie keine Funktionalität implementieren möchten, verwenden Sie eine Schnittstelle.

+2

Die letzten zwei Sätze sind Gold. :) – GalacticCowboy

+0

Das war ein großartiges Beispiel – Vamsi

1

Die .NET-Klassen Stream sind ein gutes Beispiel. Die Stream-Klasse enthält grundlegende Funktionen, die von allen Streams implementiert werden, und dann stellen bestimmte Streams spezifische Implementierungen für die tatsächliche Interaktion mit I/O bereit.

1

Die Grundidee, ist, die abstrakte Klasse zu haben, um das Skelett und die grundlegende Funktionalität zu liefern und lassen Sie einfach die konkrete Implementierung, um die genauen Details zur Verfügung zu stellen.

Angenommen, Sie haben eine Schnittstelle mit ... +20 Methoden, zum Beispiel eine List-Schnittstelle.

Wenn jemand eine Implementierung für diese Liste bereitstellen muss, muss er jedes Mal die Methode +20 implementieren.

Eine Alternative wäre, eine abstrakte Klasse zu haben, die die meisten Methoden bereits implementiert und den Entwickler nur einige davon implementieren lassen würde.

Zum Beispiel

eine unveränderbare Liste zu implementieren, muss der Programmierer nur diese Klasse zu erweitern und bieten Implementierungen für die get (int index) und Größe() -Methoden

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

In dieser Situation: get und size sind abstrakte Methoden der Entwickler muss implementieren. Der Rest der Funktionalität ist möglicherweise bereits implementiert.

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

Während diese Implementierung absurd aussehen, wäre es sinnvoll sein, eine Variable zu initialisieren:

List list = new EmptyList(); 

    foreach(Object o: in list) { 
    } 

Null-Zeiger zu vermeiden.

0

Ein Beispiel

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

     public abstract void Initialize(); 

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

      this.Initialize(); 
     } 
    } 
} 
Verwandte Themen