Komentáře
Odpověď
Problém, který jsem viděl při údržbě kódu, který využívá příznaky, je ten, že počet států rychle roste a téměř vždy existují neošetřené stavy. Jeden příklad z mé vlastní zkušenosti: Pracoval jsem na nějakém kódu, který měl tyto tři příznaky
bool capturing, processing, sending;
Tyto tři vytvořily osm států (ve skutečnosti byly dva další příznaky také). Ne všechny možné kombinace hodnot byly kódem pokryty a uživatelé viděli chyby:
if(capturing && sending){ // we must be processing as well ... }
Ukázalo se, že existují situace, kdy předpoklad v příkazu if výše bylo nepravdivé.
Příznaky mají tendenci se časem sloučit a skryjí skutečný stav třídy. Proto je třeba se jim vyhnout.
Komentáře
- +1, " je třeba se vyhnout ". Chtěl bych přidat něco o ', ale příznaky jsou v některých situacích nutné ' (někteří by mohli říci ' nutné zlo ')
- @TrevorBoydSmith Podle mých zkušeností nejsou, stačí jen o něco více, než je průměrná mozková síla, kterou byste použili příznak
- Ve vašem příkladu by to měl být jediný výčet představující stát, ne 3 booleans.
- Možná narazíte na podobný problém jako já ' m právě teď. Kromě pokrytí všech možných stavů mohou dvě aplikace sdílet stejný příznak (např. Nahrávání údajů o zákaznících). V takovém případě použije pouze jeden Uploader, nastaví jej a hodně štěstí při hledání problému v budoucnu.
Odpovědět
Zde je příklad, kdy jsou příznaky užitečné.
Mám část kódu, která generuje hesla (pomocí kryptograficky zabezpečeného generátoru pseudonáhodných čísel). Volající metody zvolí, zda nebo heslo by nemělo obsahovat velká písmena, malá písmena, číslice, základní symboly, rozšířené symboly, řecké symboly, azbuku a unicode.
U vlajek je volání této metody snadné:
var password = this.PasswordGenerator.Generate( CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);
a lze jej dokonce zjednodušit na:
var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);
Jaký by byl podpis metody bez příznaků?
public byte[] Generate( bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols, bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);
takto nazvané:
// 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);
Jak je uvedeno v komentářích, dalším přístupem by bylo použití kolekce:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LowercaseLetters, CharacterSet.UppercaseLetters, });
To je mnohem čitelnější ve srovnání se sadou true
a false
, ale stále má dvě nevýhody:
Hlavní nevýhodou je, že pro umožnění kombinovaných hodnot, jako je CharacterSet.LettersAndDigits
něco takového byste psali metodou Generate()
:
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. }
možná přepsáno takto:
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. }
Porovnejte to s tím, co máte, pomocí příznaků:
if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters) { // The password should contain lowercase letters. }
The s druhou, velmi malou nevýhodou je, že není jasné, jak by se metoda chovala, kdyby se volala takto:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LettersAndDigits, // So digits are requested two times. });
Komentáře
- Domnívám se, že OP odkazuje na booleovské nebo celočíselné proměnné, kterým přiřadíte hodnotu na určitých místech, pak dole pod sebou a poté v ortheru něco udělat nebo ne, například použít
newItem = true
pak několik řádků podif (newItem ) then
- @MainMa Zřejmě tam ' sa 3.: Verze s 8 booleovskými argumenty je to, na co jsem myslel, když jsem četl " flags " …
- Omlouváme se, ale IMHO je to perfektní případ pro řetězení metod ( en.wikipedia.org/wiki/Method_chaining), Navíc můžete použít pole parametrů (musí to být asociativní pole nebo mapa), kde každá položka v tomto poli parametrů, kterou vynecháte, použije chování výchozí hodnoty pro tento parametr. Nakonec může být volání pomocí řetězců metod nebo polí parametrů stejně stručné a expresivní jako bitové příznaky, také ne každý jazyk má bitové operátory (ve skutečnosti mám rád binární příznaky, ale místo toho bych použil metody, které jsem právě zmínil).
- Není to ' příliš OOP, že? ' vytvořím rozhraní ala: String myNewPassword = makePassword (randomComposeSupplier (new RandomLowerCaseSupplier (), new RandomUpperCaseSupplier (), new RandomNumberSupplier)); s řetězcem makePassword (dodavatel < znak > charSupplier); a dodavatel < znak > randomComposeSupplier (dodavatel < znak … dodavatelé); Nyní můžete své dodavatele znovu použít pro jiné úkoly, libovolně je skládat a zjednodušit svou metodu generatePassword, takže využívá minimální stav.
- @Dibbeke Diskuse o království podstatných jmen …
odpověď
Obrovským funkčním blokem je vůně , ne vlajky. Pokud nastavíte příznak na řádku 5, pak zkontrolujte pouze příznak na řádku 354, pak je to špatné. Pokud nastavíte příznak na řádku 8 a zkontrolujete příznak na řádku 10, je to v pořádku. Jeden nebo dva příznaky na blok kódu jsou také v pořádku, 300 příznaků ve funkci je špatných.
Odpověď
Obvykle příznaky může být zcela nahrazen nějakou příchutí strategického vzoru, s jednou implementací strategie pro každou možnou hodnotu vlajky. Díky tomu je přidávání nového chování mnohem jednodušší.
V kritických situacích s výkonem se náklady na nepřímo mohou objevit a je nutné provést dekonstrukci do jasných příznaků. To znamená, že mám potíže si vzpomenout na jediný případ, kdy jsem to vlastně musel udělat.
Odpověď
Ne, příznaky nejsou špatné nebo zlé, které je třeba za každou cenu odstranit.
Zvažte prostředí Java „s Pattern.compile (řetězec regex, příznaky int) volání. Toto je tradiční bitová maska a funguje to. Podívejte se na konstanty v Javě a kdekoli uvidíte hromadu 2 n víte, že tam jsou příznaky.
V ideálním refaktorovaném světě by místo toho bylo použito EnumSet , kde jsou konstanty místo toho hodnoty ve výčtu a jak čte dokumentace:
Prostorový a časový výkon této třídy by měl být dostatečně dobrý, aby umožňoval její použití jako vysoce kvalitní a bezpečnou alternativu k tradičním „bitovým příznakům“ založeným na int. „
V dokonalém světě se volání Pattern.compile stává Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.
Vše to znamená, jeho stále vlajky.Je mnohem snazší pracovat s Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
, než by to bylo mít Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
nebo nějaký jiný styl pokusu o to, jaké vlajky skutečně jsou a dobré pro.
Příznaky jsou často vidět při práci s věcmi na úrovni systému. Při propojení s něčím na úrovni operačního systému je pravděpodobné, že někde bude příznak – ať už je to návratová hodnota procesu, oprávnění souboru nebo příznaky otevření soketu. Pokus o refaktorování těchto instancí v honbě na čarodějnice proti vnímané vůni kódu pravděpodobně skončí s horším kódem, než kdyby někdo použil přijatý a rozuměl příznaku.
Problém nastane, když lidé zneužijí příznaky, které je hodí dohromady vytvoření sady frankenflag všech druhů nesouvisejících příznaků nebo pokus o jejich použití tam, kde vůbec příznaky nejsou.
Odpovědět
Předpokládám, že mluvíme o vlajkách v signaturách metod.
Použití jediného příznaku je dost špatné.
Pro vaše kolegy to nebude nic znamenat, když to uvidí. Budou se muset podívat na zdrojový kód metody, aby zjistili, co dělá. Pravděpodobně budete ve stejné pozici několik měsíců po řádku, když zapomenete, o čem vaše metoda byla.
Předání příznaku metodě obvykle znamená, že vaše metoda je zodpovědná za více věcí. Uvnitř metody pravděpodobně provádíte jednoduchou kontrolu v řádcích:
if (flag) DoFlagSet(); else DoFlagNotSet();
To je špatné oddělení obav a obvykle se dá najít způsob, jak to obejít.
Obvykle mám dvě samostatné metody:
public void DoFlagSet() { } public void DoFlagNotSet() { }
To bude dávat větší smysl s názvy metod, které jsou použitelné pro problém, který řešíte.
Předání více příznaků je dvakrát tak špatné. Pokud opravdu potřebujete předat několik příznaků, zvažte jejich zapouzdření ve třídě. I přesto budete stále čelit stejnému problému, protože vaše metoda pravděpodobně dělá více věcí.
Odpovědět
Příznaky a většina dočasných proměnných silně voní. S největší pravděpodobností by mohly být refaktorovány a nahrazeny metodami dotazu.
Revidováno:
Příznaky a dočasné proměnné při vyjadřování stavu by měly být refaktorovány metodám dotazu. Hodnoty stavu (booleans, ints a další primatives) by měly být téměř vždy skryté jako součást podrobností implementace.
Příznaky, které se používají pro řízení, směrování a obecný tok programu, mohou také označovat příležitost refaktorovat části řídících struktur do samostatných strategií nebo továren, nebo cokoli, co by mohlo být situačně vhodné, které nadále využívají metody dotazu.
Odpovědět
Když mluvíme o vlajkách, měli bychom vědět, že se budou během provádění programu upravovat a že ovlivní chování programu na základě jejich stavů. Dokud budeme mít nad těmito dvěma věcmi čistou kontrolu, budou fungovat skvěle.
Příznaky mohou fungovat skvěle, pokud
- Definovali jste je v příslušném rozsahu. Vhodně mám na mysli, že rozsah by neměl obsahovat žádný kód, který by je nemusel / neměl-neměnit. Nebo je kód alespoň zabezpečený (například jej nelze volat přímo zvenčí).
- Pokud je potřeba zpracovávat příznaky zvenčí a pokud existuje mnoho příznaků, můžeme kódovat obsluhu příznaků jako jediný způsob. bezpečně upravit příznaky. Tento obslužný program příznaků může sám zapouzdřit příznaky a metody jejich úpravy. To can then be made singleton and can then be shared within classes that needs access to flags.
- A konečne pro udržovatelnost, pokud existuje příliš mnoho příznaků:
- Není třeba říkat, že by měli následujte rozumné pojmenování
- Mělo by být dokumentováno s platnými hodnotami (může to být s výčty)
- Mělo by být dokumentováno s KTERÝM KÓDEM BUDE ZMĚNIT každou z nich a také s KTERÝM STAVEM při přiřazení konkrétní hodnoty k příznaku.
- KTERÝ KÓD JE SPOTŘEBUJE a CO CHOVÁNÍ bude mít za určitou hodnotu
Pokud existuje spousta příznaků, měla by předcházet dobrá designová práce, protože příznaky by pak měly hrát klíčovou roli v chování programu. Můžete přejít na State diagramy pro modelování. Taková schémata fungují také jako dokumentace a vizuální vedení při jejich řešení.
Dokud jsou tyto věci na místě, myslím, že to nepovede k nepořádku.
Odpověď
Z otázky jsem vycházel z toho, že QA znamenalo proměnné vlajky (globální), a ne bity funkčního parametru.
Existují situace kde nemáte mnoho dalších možností. Například bez operačního systému musíte vyhodnotit přerušení.Pokud k přerušení dochází velmi často a nemáte čas na zdlouhavé vyhodnocení v ISR, je nejen povoleno, ale někdy dokonce nejlepší postup nastavit pouze některé globální příznaky v ISR (měli byste trávit co nejméně času v ISR) a vyhodnotit tyto příznaky ve vaší hlavní smyčce.
Odpovědět
Nemyslím si cokoli je v programování absolutně zlé.
Existuje další situace, kdy mohou být příznaky v pořádku, což ještě zde nebyly zmíněny …
Zvažte použití uzávěrů v tomto fragmentu Javascript:
exports.isPostDraft = function ( post, draftTag ) { var isDraft = false; if (post.tags) post.tags.forEach(function(tag){ if (tag === draftTag) isDraft = true; }); return isDraft; }
Předává se vnitřní funkce do pole „Array.forEach“ nelze jednoduše „vrátit hodnotu true“.
Proto je nutné ponechat stát venku s příznakem.
newItem = true
pak některé řádky podif (newItem ) then