Kommentarer
Svar
Det problem, jeg har set, når jeg vedligeholder kode, der bruger flag, er, at antallet af stater vokser hurtigt, og at der næsten altid er uhåndterede stater. Et eksempel fra min egen erfaring: Jeg arbejdede på en kode, der havde disse tre flag
bool capturing, processing, sending;
Disse tre skabte otte stater (faktisk var der to andre flag såvel). Ikke alle mulige værdikombinationer var dækket af koden, og brugerne så fejl:
if(capturing && sending){ // we must be processing as well ... }
Det viste sig, at der var situationer, hvor antagelsen i if-sætningen ovenstående var falsk.
Flag har tendens til at blive sammensat over tid, og de skjuler klassens aktuelle tilstand. Derfor bør de undgås.
Kommentarer
- +1, " bør undgås ". Jeg vil tilføje noget om ' men flag er nødvendige i nogle situationer ' (nogle siger måske ' et nødvendigt onde ')
- @TrevorBoydSmith Efter min erfaring er de ikke, du behøver bare lidt mere end den gennemsnitlige hjernekraft, du ville bruge til et flag
- I din eksamens burde det have været et enkelt enum, der repræsenterer tilstand, ikke 3 booleanske.
- Du kommer muligvis til et lignende problem, som jeg ' m vender lige nu. Ud over at dække alle mulige stater kan to applikationer muligvis dele det samme flag (f.eks. Uploade kundedata). I dette tilfælde vil kun en uploader bruge flag, sætte det af og held og lykke med at finde problemet i fremtiden.
Svar
Her er et eksempel, når flag er nyttige.
Jeg har et stykke kode, der genererer adgangskoder (ved hjælp af en kryptografisk sikker pseudorandom-talgenerator). Opkalderen til metoden vælger, om eller ikke adgangskoden skal indeholde store bogstaver, små bogstaver, cifre, grundlæggende symboler, udvidede symboler, græske symboler, kyrilliske og unicode.
Med flag er det let at kalde denne metode:
var password = this.PasswordGenerator.Generate( CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);
og det kan endda forenkles til:
var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);
Uden flag, hvad ville metodesignaturen være?
public byte[] Generate( bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols, bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);
kaldes sådan:
// Very readable, isn"t it? // Tell me just by looking at this code what symbols do I want to be included? var password = this.PasswordGenerator.Generate( true, true, true, false, false, false, false, false);
Som bemærket i kommentarerne ville en anden tilgang være at bruge en samling:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LowercaseLetters, CharacterSet.UppercaseLetters, });
Dette er meget mere læsbart sammenlignet med sættet med true
og false
, men har stadig to ulemper:
Den største ulempe er, at for at tillade kombinerede værdier, som CharacterSet.LettersAndDigits
du skriver noget lignende i Generate()
metode:
if (set.Contains(CharacterSet.LowercaseLetters) || set.Contains(CharacterSet.Letters) || set.Contains(CharacterSet.LettersAndDigits) || set.Contains(CharacterSet.Default) || set.Contains(CharacterSet.All)) { // The password should contain lowercase letters. }
muligvis omskrevet sådan:
var lowercaseGroups = new [] { CharacterSet.LowercaseLetters, CharacterSet.Letters, CharacterSet.LettersAndDigits, CharacterSet.Default, CharacterSet.All, }; if (lowercaseGroups.Any(s => set.Contains(s))) { // The password should contain lowercase letters. }
Sammenlign dette med hvad du har ved hjælp af flag:
if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters) { // The password should contain lowercase letters. }
s Økonomisk meget lille ulempe er, at det ikke er klart, hvordan metoden opfører sig, hvis den kaldes sådan:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LettersAndDigits, // So digits are requested two times. });
Kommentarer
- Jeg mener, OP henviser til boolske eller heltal variabler, som du tildeler en værdi på bestemte steder, så nedenunder kontrollerer du derefter i orther at gøre noget eller ej, som for eksempel at bruge
newItem = true
så nogle linjer underif (newItem ) then
- @MainMa Tilsyneladende der ' sa 3.: Versionen med 8 boolske argumenter er, hvad jeg tænkte på, da jeg læste " flag " …
- Undskyld, men IMHO dette er det perfekte tilfælde til metodekædning ( da.wikipedia.org/wiki/Method_chaining), Derudover kan du bruge et parameterarray (skal være et associerende array eller kort), hvor enhver post i det parameterarray, du udelader, bruger standardværdioppførelsen for denne parameter. I sidste ende kan opkaldet via metodekædning eller parameterarrays være lige så kortfattede og udtryksfulde som bitflag, og ikke alle sprog har bitoperatorer (jeg kan faktisk godt lide binære flag, men bruger de metoder, jeg lige har nævnt i stedet for). / li>
- Det ' er ikke særlig OOP, er det? Jeg ' d laver en grænseflade ala: String myNewPassword = makePassword (randomComposeSupplier (new RandomLowerCaseSupplier (), new RandomUpperCaseSupplier (), new RandomNumberSupplier)); med streng makePassword (leverandør < Tegn > charSupplier); og leverandør < Tegn > randomComposeSupplier (leverandør < Tegn > … leverandører); Nu kan du genbruge dine leverandører til andre opgaver, komponere dem på enhver måde, du vil, og forenkle din genererePassword-metode, så den bruger minimal tilstand.
- @Dibbeke Tal om en navneordsriget …
Svar
En enorm funktionsblok er lugten , ikke flagene. Hvis du sætter flag på linje 5, skal du kun kontrollere for flag på linje 354, så er det dårligt. Hvis du sætter flag på linje 8 og tjekker for flag på linje 10, er det fint. Et eller to flag pr. Blok kode er også fint, 300 flag i en funktion er dårlig.
Svar
Normalt flag kan erstattes fuldstændigt af en eller anden smag af strategimønsteret med en implementering af en strategi for alle mulige værdier af flagget. Dette gør det meget lettere at tilføje ny adfærd.
I ydeevnekritiske situationer er omkostningerne ved indirektion muligvis overflade og gør dekonstruktion til klare flag nødvendige. Når det er sagt, har jeg svært ved at huske et enkelt tilfælde, hvor jeg faktisk skulle gøre det.
Svar
Nej, flag er ikke dårlige eller et onde, der for enhver pris skal omformuleres væk.
Overvej Java “s Pattern.compile (String regex, int flags) opkald. Dette er en traditionel bitmaske, og den fungerer. Se på konstanter i java, og uanset hvor du ser en masse 2 n ved du, at der er flag der.
I en ideel refaktoriseret verden ville man i stedet bruge en EnumSet , hvor konstanterne i stedet er værdier i enum, og som dokumentationen lyder:
Rum- og tidseffektiviteten for denne klasse skal være god nok til at muliggøre brugen som et højkvalitets, typesikkert alternativ til traditionelle int-baserede “bitflag.”
I en perfekt verden bliver dette mønster.kompilopkald til Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.
Alle når det er sagt, det er stadig flag.Det er meget nemmere at arbejde med Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
end det ville være at have Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
eller en anden form for forsøg på at gøre, hvad flag virkelig er og godt til.
Flag ses ofte, når man arbejder med ting på systemniveau. Når man interagerer med noget på operativsystemniveau, vil man sandsynligvis have et flag et eller andet sted – det være sig returværdien af en proces eller tilladelserne til en fil eller flagene til åbning af en sokkel. Forsøg på at omlægge disse forekomster væk i en eller anden heksejagt mod en opfattet kodelugt vil sandsynligvis ende med dårligere kode, end hvis man brugte accepteret og forstået flagget.
Problemet opstår, når folk misbruger flag, der kaster dem sammen og Oprettelse af et frankenflag-sæt med alle mulige ikke-relaterede flag eller forsøg på at bruge dem, hvor de slet ikke er flag.
Svar
Jeg antager, at vi taler om flag inden for metodesignaturer.
Brug af et enkelt flag er dårligt nok.
Det betyder intet for dine kolleger, når de ser det. De bliver nødt til at se på kildekoden til metoden for at fastslå, hvad den gør. Du vil sandsynligvis være i den samme position få måneder senere, når du glemmer, hvad din metode handlede om.
At sende et flag til metoden betyder normalt, at din metode er ansvarlig for flere ting. Inde i metoden foretager du sandsynligvis en simpel kontrol på linjerne:
if (flag) DoFlagSet(); else DoFlagNotSet();
Det er en dårlig adskillelse af bekymringer, og du kan normalt finde en vej rundt det.
Jeg har normalt to separate metoder:
public void DoFlagSet() { } public void DoFlagNotSet() { }
Dette giver mere mening med metodenavne, der gælder for det problem, du løser.
At sende flere flag er dobbelt så dårlig. Hvis du virkelig har brug for at videregive flere flag, end overvej at indkapsle dem i en klasse. Selv da vil du stadig stå over for det samme problem, da din metode sandsynligvis gør flere ting.
Svar
Flag og de fleste temp variabler er en stærk lugt. Mest sandsynligt kunne de refaktoriseres og erstattes med forespørgselsmetoder.
Revideret:
Flag og temp. Variabler, når de udtrykker tilstand, bør omformuleres til forespørgselsmetoder. Tilstandsværdierne (booleans, ints og andre primativer) skal næsten altid være skjult som en del af implementeringsoplysningerne.
Flag, der bruges til kontrol, dirigering og generel programflow kan også indikere mulighed for at omlægge dele af kontrolstrukturerne til separate strategier eller fabrikker eller hvad der måtte være situationelt passende, der fortsat gør brug af forespørgselsmetoderne.
Svar
Når vi taler om flag, skal vi vide, at de vil blive modificeret over tid til programudførelse, og at de vil påvirke programmets opførsel baseret på deres tilstande. Så længe vi har pæn kontrol over disse to ting, fungerer de godt.
Flag kan fungere godt, hvis
- Du har defineret dem i et passende omfang. Med passende mener jeg omfanget ikke bør indeholde nogen kode, der ikke behøver / ikke bør ændre dem. Eller i det mindste er koden sikker (for eksempel kaldes den muligvis ikke direkte udefra)
- Hvis der er behov for at håndtere flag udefra, og hvis der er mange flag, kan vi kode flaghåndtering som den eneste måde til sikkert at ændre flag. Denne flaghåndterer kan selv indkapsle flag og metoder til at ændre dem. Det kan derefter laves singleton og kan derefter deles mellem klasser, der har brug for adgang til flag.
- Og til sidst for vedligeholdelse, hvis der er for mange flag:
- Ingen grund til at sige, at de skulle følg fornuftig navngivning
- Bør dokumenteres med, hvad der er gyldige værdier (kan være med en optælling)
- Bør dokumenteres med HVILKEN KODE MODIFIERER hver af dem, og også med HVILKEN BETINGELSE vil resultere ved tildeling af en bestemt værdi til flagget.
- HVILKEN KODE FORBRUGER dem, og HVAD OPFØRER vil resultere i en bestemt værdi
Hvis der er helvede med mange flag, skal godt designarbejde gå forud, da flag derefter begynder at spille nøglerolle i programadfærd. Du kan gå efter tilstandsdiagrammer til modellering. Sådanne diagrammer fungerer også som dokumentation og visuel vejledning, mens du beskæftiger dig med dem.
Så længe disse ting er på plads, tror jeg, det ikke vil føre til rod.
Svar
Jeg antog ud fra spørgsmålet, at QA betydede flagvariabler (globale) og ikke bits i en funktionsparameter.
Der er situationer hvor du ikke har meget andre muligheder. For eksempel er du uden et operativsystem nødt til at evaluere afbrydelser.Hvis en afbrydelse kommer meget ofte, og du ikke har tid til at foretage en langvarig evaluering i ISR, er det ikke kun tilladt, men nogle gange endda bedste praksis, kun at sætte nogle globale flag i ISR (du bør bruge så lidt tid som muligt) i ISR), og for at evaluere disse flag i din hovedsløjfe.
Svar
Jeg tror ikke noget er en absolut ondskab i programmeringen nogensinde.
Der er en anden situation, hvor flag kan være i orden, som blev ikke nævnt her endnu …
Overvej brugen af lukninger i dette Javascript-uddrag:
exports.isPostDraft = function ( post, draftTag ) { var isDraft = false; if (post.tags) post.tags.forEach(function(tag){ if (tag === draftTag) isDraft = true; }); return isDraft; }
Den indre funktion, der er bestået til “Array.forEach”, kan ikke bare “returnere sandt”.
Derfor er du nødt til at holde staten uden for med et flag.
newItem = true
så nogle linjer underif (newItem ) then