Вы находитесь на странице: 1из 6

Chapter 7 Using and abusing

inheritance

Problems

Problem 7.1 Study Chapter 7

Identify the appropriate example(s) or section(s) of the chapter to illustrate each comment
made in the summary at the end of chapter 7.

Problem 7.2 Using inheritance appropriately

Reconsider the ‘deep hierarchy’ version of problem 3.3. In what ways does this violate the
requirements for implementation inheritance, and which of the anti-patterns listed in this
chapter does it contravene?

To answer this question, maybe a good start is to go back to the basic test for
implementation inheritance, which chapter 7 p13 gives as: ‘The basic test for
implementation inheritance is the IsA test. Is the proposed subclass a superclass in all
respects? Do all features of the superclass apply to the subclass, possibly with some
extensions but with minimal need for overriding?’
Applying this to example 3.3, we can ask: ‘Is a TBoxSmall a TBoxLarge, possibly with
some extensions?’ No it is not. And is a TBoxLarge a TItem, possibly with extensions?

Using and abusing inheritance (23 Sep 2006, all rights reserved) Chapter 7, Page 1
Again, no. So the deep hierarchy structure fails the IsA test.
The deep hierarchy falls foul of anti-pattern 7.1. Depending on the implementation
there may be methods in TBoxLarge that do not apply to TBoxSmall, in which case
TBoxSmall exposes methods in TBoxLarge inappropriately. (Some students did not use
the existing data fields in TBoxLarge for TBoxSmall but declared additional data fields: in
this case TBoxSmall is also exposing TBoxLarge’s unused data fields.)
The limiting visibility anti-pattern (7.2) does not apply here since it refers to writing
methods in the subclass specifically to void the matching method in the superclass. This
has not been done here.
One can argue that this also breaks the construction convenience anti-pattern (7.4).
One might also consider the role test, which is the other test for implementation
inheritance. None of these are roles of the other (a small box won’t suddenly become a
large box) and so it is valid to have all of these in the same inheritance hierarchy.
Fortunately, the shallow hierarchy meets all of the criteria above.

Problem 7.3 An interface inheritance problem

Reimplement the ‘shallow hierarchy’ version of problem 3.3, taking advantage of concepts,
such as polymorphism and abstract classes, that have been introduced after chapter 3. The
following framework may be helpful in this reimplementation.

First, the driver unit:

1 unit BoxCountU;

2 interface

3 uses
4 Windows, Messages, SysUtils, Variants, classes, Graphics,
5 Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls,
6 ItemCountU;

7 type
8 TfrmCount = class(TForm)
9 // standard RAD declarations

31 private
32 procedure DisplayValues;
33 procedure UpdateCount (APackage: TItemCount;
34 ADirection: integer);
35 end; // end TfrmCount = class(TForm)

Chapter 7, Page 2 Object orientation with Delphi (all rights reserved)


36 var
37 frmCount: TfrmCount;

38 implementation

39 uses
40 ItemU, BoxLargeU, BoxSmallU;

41 const
42 Into = 0;
43 OutOf = 1;

44 var
45 ItemCount: TItem;
46 LargeBoxCount: TBoxLarge;
47 SmallBoxCount: TBoxSmall;

48 {$R *.dfm}

49 procedure TfrmCount.btnItemsClick(Sender: TObject);


50 begin
51 UpdateCount (ItemCount, rgpItemDrctn.ItemIndex);
52 end; // end procedure TfrmCount.btnItemsClick

53 procedure TfrmCount.btnLargeBoxesClick(Sender: TObject);


54 begin
55 UpdateCount (LargeBoxCount, rgpLBoxDrctn.ItemIndex);
56 end; // end procedure TfrmCount.btnLargeBoxesClick

57 procedure TfrmCount.btnSmallBoxesClick(Sender: TObject);


58 begin
59 UpdateCount (SmallBoxCount, rgpSBoxDrctn.ItemIndex);
60 end; // end procedure TfrmCount.btnSmallBoxesClick

61 procedure TfrmCount.UpdateCount(APackage: TItemCount;


62 ADirection: integer);
63 begin
64 if ADirection = Into then
65 APackage.Add // polymorphic
66 else if ADirection = Outof then
67 APackage.Subtract; // polymorphic
68 DisplayValues;
69 end; // end procedure TfrmCount.Update

70 procedure TfrmCount.DisplayValues;
71 var
72 TotalCount: integer;
73 begin
74 lblItems.Caption := IntToStr(ItemCount.GetCount);
75 lblLargeBoxes.Caption := IntToStr(LargeBoxCount.GetCount);
76 lblSmallBoxes.Caption := IntToStr(SmallBoxCount.GetCount);
77 TotalCount := ItemCount.GetTotal +
78 LargeBoxCount.GetTotal + SmallBoxCount.GetTotal;
79 lblTotal.Caption := IntToStr(TotalCount);
80 end; // end procedure TfrmCount.DisplayValues

Using and abusing inheritance (23 Sep 2006, all rights reserved) Chapter 7, Page 3
81 procedure TfrmCount.bmbResetClick(Sender: TObject);
82 begin
83 ItemCount.ZeroCount;
84 SmallBoxCount.ZeroCount;
85 LargeBoxCount.ZeroCount;
86 DisplayValues;
87 end; // end procedure TfrmCount.bmResetClick

88 initialization
89 ItemCount := TItem.Create;
90 LargeBoxCount := TBoxLarge.Create;
91 SmallBoxCount := TBoxSmall.Create;

92 end. // end unit BoxCountU

Now the abstract class defining the interface:

1 unit ItemCountU;

2 interface

3 type
4 TItemCount = class(TObject)
5 private
6 FCount: integer;
7 public
8 procedure Add;
9 procedure Subtract;
10 function GetCount: integer;
11 function GetTotal: integer; virtual; abstract;
12 procedure ZeroCount;
13 end; // end TItemCount = class(TObject)

14 implementation

15 { Implement the concrete method(s), if any }

32 end. // end unit ItemCountU

{ TItemCount }

procedure TItemCount.Add;
begin
Inc(FCount);
end; // end procedure TItemCount.Add

procedure TItemCount.Subtract;
begin
Inc(FCount, -1);
end; // end procedure TItemCount.Subtract

procedure TItemCount.ZeroCount;
begin
FCount := 0;

Chapter 7, Page 4 Object orientation with Delphi (all rights reserved)


end; // end procedure TItemCount.ZeroCount

function TItemCount.GetCount: integer;


begin
Result := FCount;
end; // end function TItemCount.GetCount

The concrete classes:

1 unit ItemU;

2 interface

3 uses ItemCountU;

4 type
5 TItem = class(TItemCount)
6 public
7 function GetTotal: integer; override;
8 end; // end TItem = class(TItemCount)

9 implementation

10 { TItem }

11 { Implement the concrete methods(s), if any }

15 end. // end ItemU

function TItem.GetTotal: integer;


begin
Result := GetCount;
end; // end function TItem.GetTotal

1 unit BoxLargeU;

2 interface

3 uses ItemCountU;

4 type
5 TBoxLarge = class(TItemCount)
6 public
7 function GetTotal: integer; override;
8 end; // end TBoxLarge = class(TItemCount)

9 implementation

10 { TBoxLarge }

11 const
12 NoInBox = 12;

Using and abusing inheritance (23 Sep 2006, all rights reserved) Chapter 7, Page 5
13 { Implement the concrete methods(s), if any }

17 end. // end BoxLargeU

function TBoxLarge.GetTotal: integer;


begin
Result := GetCount * NoInBox;
end; // end function TBoxLarge.GetTotal

1 unit BoxSmallU;

2 interface

3 uses ItemCountU;

4 type
5 TBoxSmall = class(TItemCount)
6 public
7 function GetTotal: integer; override;
8 end; // end TBoxSmall = class(TItemCount)

9 implementation

10 { TBoxSmall }

11 const
12 NoInBox = 4;

13 { Implement the concrete methods(s), if any }

17 end. // end BoxSmallU

function TBoxSmall.GetTotal: integer;


begin
Result := GetCount * NoInBox;
end; // end function TBoxSmall.GetTotal

The framework given above effectively guides one to adopt the same approach as given in
the assignment discussion of the deep hierarchy version of problem 3.3. The assignment
discussion of the shallow hierarchy version of problem 3.3 presents another variation of a
well-structured OO approach.

Chapter 7, Page 6 Object orientation with Delphi (all rights reserved)

Вам также может понравиться