2012-01-10 10 views
6

Quiero escribir un TCheckBox y TRadioButton descendientes que tienen 3 métodos idénticos.¿Cómo implementar métodos idénticos con 2 y más clases?

TMyCheckBox = class(TCheckBox) 
    procedure DoSomething1; 
    procedure DoSomething2; 
    procedure WMSize(var Message: TWMSize); message WM_SIZE; 
end; 

TMyRadioButton = class(TRadioButton) 
    procedure DoSomething1; 
    procedure DoSomething2; 
    procedure WMSize(var Message: TWMSize); message WM_SIZE; 
end; 

// the following procedures are common for both classes, so in fact 
// TMyCheckBox.DoSomething1 do the same as TMyRadioButton.DoSomething1 

procedure DoSomething1; 
begin 
    // here is the same code for TMyCheckBox as well as for TMyRadioButton 
    // but I don't want to write the same code many times but implement it 
    // for both classes at once in some common way 
end; 

procedure DoSomething2; 
begin 
    // here is the same code for TMyCheckBox as well as for TMyRadioButton 
    // but I don't want to write the same code many times but implement it 
    // for both classes at once in some common way 
end; 

procedure WMSize(var Message: TWMSize); message WM_SIZE; 
begin 
    // here is the same code for TMyCheckBox as well as for TMyRadioButton 
    // but I don't want to write the same code many times but implement it 
    // for both classes at once in some common way 
end; 

¿Cómo puedo hacer esto?

+0

¿Se refiere a declaraciones idénticas (usando la interfaz) o implementaciones idénticas (usando el mismo antecesor)? – Kromster

+0

@Krom, esa es una buena pregunta. Lo que realmente quise decir es implementaciones idénticas. – ZigiZ

+0

El debe mostrarnos la implementación para obtener una respuesta válida. –

Respuesta

11

Defina una interfaz digamos IDoSomething con las tres firmas de método.

a continuación, cambiar su declaración de la clase a

TMyCheckBox = class(TCheckBox, IDoSomething) 

y luego poner en práctica.

Si las implementaciones son comunes o muy cercanas.

A continuación, defina una clase de ayuda TDoSomething y luego delegue el trabajo.

p. Ej.

Procedure TMyCheckBox.DoSomething1; // implements IDoSomething1 
Begin 
    TDoSomething.DoSomething1(Self); // given class method will suffice. 
End; 

Métodos de clase en delphi, equivalente a métodos estáticos en otros idiomas.

Type 
    TDoSomethingHelper = Class(TObject) 
    Public 
     Class Procedure DoSomething1(aComponent : TComponent); 
    End; 

... 
implementation 

Class Procedure TDoSomethingHelper.DoSomething1(aComponent : TComponent); 
Begin 
    aComponent.Tag = 27; 
End; 
+0

10x Lo intentaré. – ZigiZ

+0

¿Cómo puedo definir dicha clase de ayuda en D7? ¿Se supone que el 'DoSomething1' es un método de clase? – ZigiZ

+0

Espere amplificaré –

8

Está buscando la herencia de implementación en lugar de la herencia de la interfaz. Esto solo se puede lograr en Delphi si puedes derivar clases de un único ancestro común. Esta limitación es inherente porque el lenguaje solo admite herencia única.

Lo mejor que puede hacer es algo como esto:

type 
    TMyWinControlExtender = class 
    private 
    FTarget: TWinControl; 
    public 
    constructor Create(Target: TWinControl); 
    procedure WMSize(var Message: TWMSize; out CallInherited: Boolean); 
    procedure DoSomething; 
    end; 

    TMyCheckBox = class(TCheckBox) 
    private 
    FExtender: TMyWinControlExtender; 
    protected 
    procedure WMSize(var Message: TWMSize); message WM_SIZE; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    procedure DoSomething; 
    end; 

    TMyRadioButton = class(TRadioButton) 
    private 
    FExtender: TMyWinControlExtender; 
    protected 
    procedure WMSize(var Message: TWMSize); message WM_SIZE; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    procedure DoSomething; 
    end; 

{ TMyWinControlExtender } 

constructor TMyWinControlExtender.Create(Target: TWinControl); 
begin 
    inherited Create; 
    FTarget := Target; 
end; 

procedure TMyWinControlExtender.WMSize(var Message: TWMSize; out CallInherited: Boolean); 
begin 
    if FTarget.... then 
    .... 
    CallInherited := ...; 
    //etc. 
end; 

procedure TMyWinControlExtender.DoSomething; 
begin 
    if FTarget.... then 
    .... 
    //etc. 
end; 

{ TMyCheckBox } 

constructor TMyCheckBox.Create(AOwner: TComponent); 
begin 
    inherited; 
    FExtender := TMyWinControlExtender.Create(Self); 
end; 

destructor TMyCheckBox.Destroy; 
begin 
    FExtender.Free; 
    inherited; 
end; 

procedure TMyCheckBox.DoSomething; 
begin 
    FExtender.DoSomething; 
end; 

procedure TMyCheckBox.WMSize(var Message: TWMSize); 
var 
    CallInherited: Boolean; 
begin 
    FExtender.WMSize(Message, CallInherited); 
    if CallInherited then 
    inherited; 
end; 

y lo mismo para TMyRadioButton etc.

Ahora, usted podría utilizar interfaces y delegación a reducir parte de la plancha de caldera, pero no hay manera para eso ayudar con un manejador de mensaje como WMSize.

+1

10x David. este código se ve realmente bien, especialmente cómo manejas el WMSize. Se puede hacer con métodos de clase simples/o TProcedure (pasando 'Self' como ref) más o menos lo que estoy haciendo hoy. lo que esperaba era "herencia múltiple" (usando Interfaces), pero ahora entiendo que no hay magia aquí. – ZigiZ

+1

Sí de hecho. Sin herencia múltiple de implementación en Delphi.Pocos idiomas lo admiten y, de hecho, a menudo causa más problemas de los que merece la pena. –

Cuestiones relacionadas