17

私は古いライブラリを完全に書き直していますが、この状況をどのように処理するかわかりません(理解するために、すべてが自転車の例えを歓迎します):

私は次のクラスを持っています:

  • TBike-バイク自体
  • TBikeWheel-バイクのホイールの1つ
  • TBikeWheelFrontそしてTBikeWheelBack、両方とも継承しTBikeWheel、その上に必要な特定のものを実装します

これは非常に簡単ですが、今度は複数の種類の自転車を作成することにしました。各自転車には独自の種類のホイールがあります。通常の前輪/後輪と同じ機能に加えて、その自転車に固有の機能を備えています。

  • TBikeXYZ-から継承TBike
  • TBikeWheelXYZ-から継承TBikeWheel

そして、ここに私の問題があります: (XYZホイールの特定のメソッドを取得するために)からTBikeWheelFrontXYZ継承TBikeWheelXYZする必要がありますが、(前輪の特定のメソッドを取得するために)からも継承する必要がありTBikeWheelFrontます。

ここでの私の質問は、それを実装しない方法でどのように実装できるかということです。

  1. ハックのように感じる
  2. 同じコードを何度か書き直さなければならない
4

10 に答える 10

19

Delphiは多重継承をサポートしていません。ただし、クラスは複数のインターフェイスをサポート/実装でき、インターフェイスの実装を委任できるため、複数の継承をシミュレートできます。

于 2009-08-14T05:37:09.793 に答える
17

インターフェイスを使用します。このようなもの(あなたの説明に基づいて、私の頭のてっぺんから.....)

type

  IBikeWheel = interface
    ...
  end;

  IXYZ = interface
    ...
  end;

  IFrontWheel = interface(IBikeWheel)
    ...
  end;


  TBike = class
    ...
  end;

  TBikeWheel = class(TObject, IBikeWheel);

  TBikeWheelXYZ = class(TBikeWheel, IXYZ);

  TBikeFrontWheelXYZ = class(TBikeWheelXYZ, IFrontWheel);

次に、古い(おそらくC / C ++)ライブラリの対応するクラスが実行することを実行するインターフェイスのクラスを実装し、対応するクラスのコンストラクターでそれらをインスタンス化します。

于 2009-08-14T06:08:41.727 に答える
8

ポリモーフィズムを使用して、各「もの」をそれ自体でオブジェクト階層として実装し、次にそのオブジェクトにオブジェクトプロパティを順番に追加します。したがって、ホイールの階層とバイクの階層を作成します。次に、祖先の自転車オブジェクトのフィールドとして自転車にホイールを追加します。下記参照。

  TBikeWheel = class
  TBikeWheelXYZ = class( TBikeWheel ) 

  TBike = class
    FFrontWheel : TBikeWheel;
    property FrontWheel : TBikeWheel
      read FrontWhell  

  TBikeABC = class( TBike)
    constructor Create;
  end;

  constructor TBikeABC.Create;
  begin
    inherited;
    FFrontWheel := TBikeWheel.Create;
  end;

  TBikeXYZ = class( TBike)
    constructor Create;
  end;

  constructor TBikeXYZ.Create;
  begin
    inherited;
    FFrontWheel := TBikeWheelXYZ.Create;
  end;
于 2009-08-14T10:00:54.253 に答える
5

ブライアンフロストの提案のバリエーション:

  TBikeWheel = class
  TBikeWheelXYZ = class( TBikeWheel ) 

  TBike = class
    FFrontWheel : TBikeWheel;
  protected
    function CreateWheel: TBikeWheel; virtual;
  public
    property FrontWheel : TBikeWheel
      read FrontWheel  
  end;

  TBikeABC = class( TBike)
  protected
    function CreateWheel: TBikeWheel; override;
  end;

  function TBikeABC.CreateWheel: TBikeWheel;
  begin
    result := TBikeWheel.Create;
  end;

  TBikeXYZ = class( TBike)
  protected
    function CreateWheel: TBikeWheel; override;
  end;

  function TBikeXYZ.CreateWheel: TBikeWheel;
  begin
    result := TBikeWheelXYZ.Create;
  end;
于 2009-08-14T10:54:41.853 に答える
4

基本的に-できません。Delphiは多重継承をサポートしていません。

そのジレンマが残っているので、問題は次のとおりです。インターフェイスの使用を回避できるような方法で、そのライブラリをリファクタリングできるでしょうか。多重継承は主に関数とメソッドに関するものですか?もしそうなら-インターフェースを使用してください。Delphiは、クラスで複数のインターフェイスをサポートできます。

多重継承がクラスの実際の機能を継承することに関するものである場合、おそらくより大規模なリファクタリングを検討していると思います。おそらくいくつかの追加のインターフェースがスローされた状態で、単一の基本クラスから継承できるように、これらの機能依存性を分割する方法を見つける必要があります。

申し訳ありませんが、簡単な答えを提供することはできません-それはそれの現実です。

マーク

于 2009-08-14T05:21:19.810 に答える
3

TBikeWheelFrontのサブクラスであるが、IFrontWheelを実装するように、TBikeWheelFrontからIFrontWheelなどのインターフェイスを抽出してみることができます。次に、TBikeWheelXYZはTBikeWheelを継承し、TBikeWheelFrontXYZはTBikeWheelXYZを継承し、IFrontWheelを実装します。

次に、クラスTFrontwheelを定義して、インターフェースと同じメソッドを与えることができますが、ここでそれらを実装します。次に、TBikeWheelFrontとTBikeWheelXYZはタイプTFrontwheelのプライベートメンバーを取得し、それらのIFrontWheel実装は単にプライベートメンバーメソッドに委任します。

このように、二重の実装はありません。

于 2009-08-14T05:58:08.643 に答える
2

新しいバージョンのDelphiのもう1つの方法は、構成モデルでジェネリックスを活用することです。TBarAこれは、複数の基本クラス(およびTBarBこの例では)に変更のためにアクセスできない場合(つまり、フレームワークまたはライブラリクラス)に特に役立ちます。たとえば(簡潔にするために、ここでは必要なdestructorinTFoo<T>は省略されていることに注意してください):

program Project1;

uses SysUtils;

{$APPTYPE CONSOLE}

type    
  TFooAncestor  = class
    procedure HiThere; virtual; abstract;
  end;
  TBarA = class(TFooAncestor)
    procedure HiThere; override;
  end;
  TBarB = class(TFooAncestor)
    procedure HiThere; override;
  end;
  TFoo<T: TFooAncestor, constructor> = class
    private
      FFooAncestor: T;
    public
      constructor Create;
      property SomeBar : T read FFooAncestor write FFooAncestor;
  end;

procedure TBarA.HiThere;
begin
  WriteLn('Hi from A');
end;

procedure TBarB.HiThere;
begin
  WriteLn('Hi from B');
end;

constructor TFoo<T>.Create;
begin
  inherited;
  FFooAncestor := T.Create;
end;

var
  FooA : TFoo<TBarA>;
  FooB : TFoo<TBarB>;
begin
  FooA := TFoo<TBarA>.Create;
  FooB := TFoo<TBarB>.Create;
  FooA.SomeBar.HiThere;
  FooB.SomeBar.HiThere;
  ReadLn;
end.
于 2014-08-06T12:36:23.320 に答える
1

コードを数回繰り返さず、分離されたコードが必要な場合は、この方法を試すことができます。

type
   TForm1 = class(TForm)
    btnTest: TButton;
    procedure btnTestClick(Sender: TObject);
   private
      { Private declarations }
   public
      { Public declarations }
   end;

   TBike = class
   end;

   IBikeWheel = interface
      procedure DoBikeWheel;
   end;

   TBikeWheel = class(TInterfacedObject, IBikeWheel)
   public
      procedure DoBikeWheel;
   end;

   IBikeWheelFront = interface
      procedure DoBikeWheelFront;
   end;

   TBikeWheelFront = class(TInterfacedObject, IBikeWheelFront)
   public
      procedure DoBikeWheelFront;
   end;

   IBikeWheelBack = interface
   end;

   TBikeWheelBack = class(TInterfacedObject, IBikeWheelBack)
   end;

   TBikeWheelFrontXYZ = class(TInterfacedObject, IBikeWheel, IBikeWheelFront)
   private
      FIBikeWheel: IBikeWheel;
      FBikeWheelFront: IBikeWheelFront;
   public
      constructor Create();
      property BikeWheel: IBikeWheel read FIBikeWheel implements IBikeWheel;
      property BikeWheelFront: IBikeWheelFront read FBikeWheelFront implements IBikeWheelFront;
   end;

var
   Form1: TForm1;

implementation

{$R *.DFM}

{ TBikeWheel }

procedure TBikeWheel.DoBikeWheel;
begin
   ShowMessage('TBikeWheel.DoBikeWheel');
end;

{ TBikeWheelFrontXYZ }

constructor TBikeWheelFrontXYZ.Create;
begin
   inherited Create;
   Self.FIBikeWheel := TBikeWheel.Create;
   Self.FBikeWheelFront := TBikeWheelFront.Create;
end;

{ TBikeWheelFront }

procedure TBikeWheelFront.DoBikeWheelFront;
begin
   ShowMessage('TBikeWheelFront.DoBikeWheelFront');
end;

procedure TForm1.btnTestClick(Sender: TObject);
var
   bikeWhell: TBikeWheelFrontXYZ;
begin
   bikeWhell := nil;
   try
      try
         bikeWhell := TBikeWheelFrontXYZ.Create;
         IBikeWheelFront(bikeWhell).DoBikeWheelFront;
         IBikeWheel(bikeWhell).DoBikeWheel;
      except
         on E: Exception do
         begin
            raise;
         end;
      end;
   finally
      if Assigned(bikeWhell) then FreeAndNil(bikeWhell);
   end;                                          
end;
于 2014-08-06T16:29:46.857 に答える
0

申し訳ありませんが、Delphiは多重継承をサポートしていません。

于 2015-03-20T13:27:32.483 に答える
0

次の手順を提案したいと思います。

  1. またはのいずれかTBikeWheelFrontXYZからクラスを継承します(Delphiでは、上記の回答で述べたように多重継承は不可能であるため)。TBikeWheelXYZTBikeWheelFront

  2. 親クラスの1つ、TBikeWheelXYZまたはTBikeWheelFrontクラスのクラスヘルパーに変換しTBikeWheelます。

  3. TBikeWheelFrontXYZクラスが宣言されているユニットにクラスヘルパーユニットを追加します。

于 2021-03-01T09:13:06.503 に答える