Tải bản đầy đủ - 0 (trang)
Chapter 36.  Prefer providing abstract interfaces

Chapter 36.  Prefer providing abstract interfaces

Tải bản đầy đủ - 0trang

Summary

Loveabstractart:Abstractinterfaceshelpyoufocusongetting

anabstractionrightwithoutmuddlingitwithimplementationor

statemanagementdetails.Prefertodesignhierarchiesthat

implementabstractinterfacesthatmodelabstractconcepts.



Discussion

Prefertodefineandinheritfromabstractinterfaces.Anabstract

interfaceisanabstractclassmadeupentirelyof(pure)virtual

functionsandhavingnostate(memberdata)andusuallyno

memberfunctionimplementations.Notethatavoidingstatein

abstractinterfacessimplifiestheentirehierarchydesign(see

[Meyers96]forexamples).

PrefertofollowtheDependencyInversionPrinciple(DIP;see

[Martin96a]and[Martin00]).TheDIPstatesthat:

High-levelmodulesshouldnotdependuponlow-level

modules.Rather,bothshoulddependuponabstractions.

Abstractionsshouldnotdependupondetails.Rather,details

shoulddependuponabstractions.

RespectingtheDIPimpliesthathierarchiesshouldberootedin

abstractclasses,notconcreteclasses.(SeeItem35.)The

abstractbaseclassesmustworryaboutdefiningfunctionality,

notaboutimplementingit.Putanotherway:Pushpolicyupand

implementationdown.

TheDependencyInversionPrinciplehasthreefundamental

designbenefits:

Improvedrobustness:Thelessstablepartsofasystem

(implementations)dependonmorestableparts

(abstractions).Arobustdesignisoneinwhichchanges

havelocalizedeffect.Inafragilesystem,ontheotherhand,

asmallchangeripplesinunfortunatewaysthrough

unexpectedpartsofthesystem.Thisisexactlywhat

happenswithdesignsthathaveconcretebaseclasses.



Greaterflexibility:Designsbasedonabstractinterfacesare

generallymoreflexible.Iftheabstractionsareproperly

modeled,itiseasytodevisenewimplementationsfornew

requirements.Onthecontrary,adesignthatdependson

manyconcretedetailsisrigid,inthatnewrequirements

leadtocorechanges.

Goodmodularity:Adesignrelyingonabstractionshasgood

modularitybecauseitsdependenciesaresimple:Highly

changeablepartsdependonstableparts,notviceversa.At

theotherextreme,adesignthathasinterfacesmixedwith

implementationdetailsislikelytosportintricatewebsof

dependencythatmakeithardtoreapplyasaunittoplug

intoanothersystem.

TherelatedLawofSecondChancesstates:"Themostimportant

thingtogetrightistheinterface.Everythingelsecanbefixed

later.Gettheinterfacewrong,andyoumayneverbeallowedto

fixit."[Sutter04]

Typically,chooseapublicvirtualdestructortoenable

polymorphicdeletion(perItem50),unlessyouuseanobject

brokersuchasCOMorCORBAthatusesanalternatememory

managementmechanism.

Bewaryaboutusingmultipleinheritanceofclassesthatarenot

abstractinterfaces.Designsthatusemultipleinheritancecanbe

veryexpressive,butarehardertogetrightandeasiertoget

wrong.Inparticular,statemanagementisparticularlyhardin

designsusingmultipleinheritance.

AsnotedinItem34),inheritingfromatypecanalsocause

namelookupcoupling:subtlypullinginfunctionsfromthe

namespaceofthattype.(SeealsoItem58.)



Examples

Example:Backupprogram.Innaùvedesigns,high-level

componentsdependonlow-leveldetails.Forexample,anilldesignedbackupprogrammighthaveanarchivingcomponent

thatdependsdirectlyontypesorroutinesthatreadthe

directorystructureandothersthatwritedataonthetape.

Adaptingsuchaprogramtoanewfilesystemandbackup

hardwarewouldincursignificantredesign.

Ifthelogicofthebackupsystemisdesignedaroundwelldesignedabstractionsofafilesystemandbackupdevice,no

redesignisneededonlynewimplementationsoftheabstract

interfacesmustbeaddedandpluggedintothesystem.As

shouldbenatural,newrequirementsaremetbynewcode;new

requirementsshouldnotcausereworkonexistingcode.



Exceptions

Theemptybaseoptimizationisoneinstancewheninheritance

(preferablynonpublic)isusedforpurelyoptimizationpurposes.

(ButseeItem8.)

Itwouldappearthatpolicy-baseddesignshaveahigh-level

componentdependonimplementationdetails(thepolicies).

However,thatisonlyauseofstaticpolymorphism.Theabstract

interfacesarethere,exceptthattheyareimplicit,notexplicitly

statedviapurevirtualfunctions.



References

[Alexandrescu01][Cargill92]pp.12-15,215-218[Cline99]

Đ5.18-20,21.13[Lakos96]Đ6.4.1[Martin96a][Martin00]

[Meyers96]Đ33[Stroustrup00]Đ12.3-4,Đ23.4.3.2,

Đ23.4.3.5,Đ24.2-3,Đ25.3,Đ25.6[Sutter04]Đ17



37.Publicinheritanceissubstitutability.

Inherit,nottoreuse,buttobereused

Summary

Discussion

Exceptions

References



Summary

Knowwhat:Publicinheritanceallowsapointerorreferenceto

thebaseclasstoactuallyrefertoanobjectofsomederived

class,withoutdestroyingcodecorrectnessandwithoutneeding

tochangeexistingcode.

Knowwhy:Don'tinheritpubliclytoreusecode(thatexistsin

thebaseclass);inheritpubliclyinordertobereused(by

existingcodethatalreadyusesbaseobjectspolymorphically).



Discussion

Despitetwodecadesofobject-orienteddesignknowledge,the

purposeandpracticeofpublicinheritancearestillfrequently

misunderstood,andmanyusesofinheritanceareflawed.

Publicinheritancemustalwaysmodel"is-a"("works-like-a")

accordingtotheLiskovSubstitutionPrinciple(see[Liskov88]):

Allbasecontractsmustbefulfilled,andsoalloverridesof

virtualmemberfunctionsmustrequirenomoreandpromiseno

lessthantheirbaseversionsiftheyaretosuccessfullyfulfillthe

base'scontract.CodeusingapointerorreferencetoaBase

mustbehavecorrectlyevenwhenthatpointerorreference

actuallypointstoaDerived.

Misuseofinheritancedestroyscorrectness.Incorrectly

implementedinheritancemosttypicallygoesastraybyfailingto

obeytheexplicitorimplicitcontractthatthebaseclass

establishes.Suchcontractscanbesubtle,andwhenthey

cannotbeexpresseddirectlyincodetheprogrammermusttake

extracare.(Somepatternshelptodeclaremoreintentincode;

seeItem39)

Todistillafrequentlycitedexample:Considerthattwoclasses

SquareandRectangleeachhavevirtualfunctionsforsetting

theirheightandwidth.ThenSquarecannotcorrectlyinherit

fromRectangle,becausecodethatusesamodifiable

RectanglewillassumethatSetWidthdoesnotchangethe

height(whetherRectangleexplicitlydocumentsthatcontract

ornot),whereasSquare::SetWidthcannotpreservethat

contractanditsownsquarenessinvariantatthesametime.But

RectanglecannotcorrectlyinheritfromSquareeither,ifclients

ofSquareassumeforexamplethataSquare'sareaisitswidth

squared,oriftheyrelyonsomeotherpropertythatdoesn't

holdforRectangles.



The"is-a"descriptionofpublicinheritanceismisunderstood

whenpeopleuseittodrawirrelevantreal-worldanalogies:A

square"is-a"rectangle(mathematically)butaSquareisnota

Rectangle(behaviorally).Consequently,insteadof"is-a,"we

prefertosay"works-like-a"(or,ifyouprefer,"usable-as-a")to

makethedescriptionlesspronetomisunderstanding.

Publicinheritanceisindeedaboutreuse,butnotthewaymany

programmersseemtothink.Asalreadypointedout,the

purposeofpublicinheritanceistoimplementsubstitutability

(see[Liskov88]).Thepurposeofpublicinheritanceisnotfor

thederivedclasstoreusebaseclasscodetoimplementitselfin

termsofthebaseclass'scode.Suchanis-implemented-interms-ofrelationshipcanbeentirelyproper,butshouldbe

modeledbycompositionor,inspecialcasesonly,bynonpublic

inheritance(seeItem34).

Putanotherway:Whendynamicpolymorphismiscorrectand

appropriate,compositionisselfish;inheritanceisgenerous.

Anewderivedclassisanewspecialcaseofanexistinggeneral

abstraction.Existing(dynamically)polymorphiccodethatuses

aBase&orBase*bycallingBase'svirtualfunctionsshouldbe

abletoseamlesslyuseobjectsofMyNewDerivedTypethat

inheritsfromBase.Thenewderivedtypeaddsnewfunctionality

totheexistingcode,whichdoesnotneedtobechangedbut

canseamlesslyincreaseitsfunctionalitywhennewderived

objectsarepluggedin.

Newrequirementsshouldnaturallybemetbynewcode;new

requirementsshouldnotcausereworkonexistingcode.(See

Item36)

Beforeobjectorientation,ithasalwaysbeeneasyfornewcode

tocallexistingcode.Publicinheritancespecificallymakesit

easierforexistingcodetoseamlesslyandsafelycallnewcode.

(Sodotemplates,whichprovidestaticpolymorphismthatcan

blendwellwithdynamicpolymorphism;seeItem64)



Exceptions

Policyclassesandmixinsaddbehaviorbypublicinheritance,

butthisisnotabusingpublicinheritancetomodelisimplemented-in-terms-of.



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 36.  Prefer providing abstract interfaces

Tải bản đầy đủ ngay(0 tr)

×