Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

Ars programatica

Udělat dobrý sotware je řemeslo, udělat výjimečný software je umění
Konfigurace CodeRush Xpress

Rozhodl jsem sevyzkoušet rozšíření pro Visual Studio z rodiny „productivity tools" CodeRushXpress. Jedná se o bezplatnou a notně očesanou verzi placeného nástrojeCodeRush, který jsem ke svému velkému překvapení vyhodnotil jako užitečnější,než vyhlášený ReSharper. Verze zdarma je sice určena především k tomu, abyuživatele namlsala, přesto však není zcela nepoužitelná, nabízí některé úpravykódu a především mé oblíbené zvýrazňování výskytů identifikátoru. Na rozdíl od „dospělé"verze jsem však po nainstalování marně hledal možnosti konfigurace - v Optionsnic a samostatné menu, stejně jako vlastní toolbar se nekonal; editaci konfiguračníchXML souborů jsem předem zamítl). Nakonec pomohl help: konfigurační dialog proCodeRush Xpress se vyvolá klávesovou zkratkou Ctrl+Alt+Shift+O

Posted: 19. dubna 2010 13:03 by pbouda | 3 Comments
Vedeno pod: ,
Seznam changesetů v TFS za období

Seznam všech (mých) changesetů vytvořených v nějakém časovém intervalu od-do lze získat z příkazové řádky utilitou tf.exe následovně:

tf history * /r /user:username /version:Dyyyy-mm-dd~Dyyyy-dd-mm

 

Interval se zadává jako specifická verze, datum je určeno prefixem "D" a data jsou oddělena "~" (vlnovkou). Je-li zadáno pouze jedno datum, má význam do.

Posted: 7. prosince 2009 14:35 by pbouda | 2 Comments
Vedeno pod: ,
WCF a WF v .NET 4.0
Starší, nikoliv však zastaralé články a připrovavovaných novinkách v .NET 4.0 (VS 2010)
 
(via Mike Taulty's Blog)
Když uživatel nemůže pracovat s TFS-WA, i když má všechna práva

Expozé

Tento příspěvěk by se stejně dobře mohl jmenovat "lovcovy zápisky z honu na duchy". Bude asi trochu zmatečný, stejně jako moje ponětí o tom, co se vlastně dělo a čím že jsem to nakonec vyřešil.

Úvod do problému

Chtěl jsem dalšímu uživateli umožnit přístup do TFS přes TFS Web Access, zopakoval jsem tedy postup, který v minulosti zafungoval u jiného uživatele, tj. přidal jsem ho do skupiny Contributors příslušného projektu. Ale ouha - to co předtím fungovalo, tentokráte naprosto selhalo. Každý jeho pokus o přístup do TFS skončil s chybou "Unable to create workitemstore see exceptions for more details."

InnerException jsem se samozřejmě nikde nedohledal, ale občas se podařilo v TFS-WA vymámit tuto chybu: "RebuildCallersViews: Connecting Domain User could not be validated. ---> RebuildCallersViews: Connecting Domain User could not be validated. ---> RebuildCallersViews: Connecting Domain User could not be validated."

To už bylo lepší, ale pořád málo

Vyšetřování

Po chvíli práce s vyhledávačem jsem zjistil, že chyba je pravděpodobně v synchronizaci informací mezi doménou a tabulí  TFSWorkItemTracking..ADObjects. To lze ověřit tímto SQL:

select next_id - 1 as GSSMaxIdenditySeqId from TFSIntegration..tbl_sequence_ids where name = 'identity_cache'
select max(seqid) as WITMaxIdentitySeqId, MAX(LastSyncUTC) as LastSyncUTC from TFSWorkItemTracking..ADObjects

Pokud jsou data synchronní, oba dotazy by měly vrátit stejné ID. V mém případě stejná nebyla, takže stopa.

Jenže proč k synchronizaci nedochází?

Nejprve jsem zkontroloval joby v SQL serveru a zjistil, že některé z nich jsou nastaveny tak, aby běžely pod účtem kolegy, který již před delší dobou odešel. Přenastavil jsem je tedy na platný účet - a nic.

Vyšetřování pokračuje

Po další chvíli práce s vyhledávačem jsem se dostal k tomuto SQL:

select [address], [domain], [account_name], [deleted]
from TfsIntegration..tbl_subscription s
join TfsIntegration..tbl_security_identity_cache i
on s.subscriber = i.sid
where s.delivery_type = 2

Account name by měl být platný účet a příznak deleted by měl být false (respektive 0). A zde byl opět již neexistující účet bývalého kolegy. Zajásal jsem a tbl_subscription.account_name nastavil na SID platného účtu - a nic.

Řešení?

Poslední krok, po kterém se tabule sesynchronizovaly a nově přidaný uživatel se mohl konečně přihlásit, byl restart IIS a smazání cache TFS-WA (ta je standardně v \Program Files\Microsoft Visual Studio 2008 Team System Web Access\Cache\).

A proč řešení s otazníkem? Protože si nejsem po všem tom laborování jistý, co přesně bylo rozhodující pro vyřešení problému s přihlašováním, zda všechno (i špatný account jobu), nebo jen část (oprava v tbl_subsriptions a restart IIS), a jestli jsem náhodou neudělal ještě něco důležitého (například update TfsWorkItemTracking.dbo.Persons set fRebuildWrite = 1, kterýžto SQL jsem objevil na jedné otevřené záložce browseru), na co jsem mezitím zapomněl.

 

Posted: 15. června 2009 15:29 by pbouda | 0 Comments
Vedeno pod: ,
Chybná stavová ikona u souboru v TFS

Někdy se stává, že v Solution Exploreru jsou u souborů uložených v TFS zobrazeny špatné stavové ikony, které naznačují, že soubor je check-out někým jiným, přestože to není pravda (jak lze ověřit přes Source Control Explorer). Příkaz Refresh Status z menu File / Source Control nepomůže, nepomůže ani znovuvytvořit workspace... Ne že by kvůli tomu nešlo kompilovat, nebo tak něco, ale mate to.

Nakonec jsem s největší pravděpodobností odpověď nalezl: stává se to u souborů, které jsou shelvsetu. Každopádně zrušit shelvset pomohlo, jenom mne mate, že u klienta jsem měl shelvsetů nepočítaně a přitom se ikonky zobrazovaly správně.

Integrace WinMerge do Visual Studia

Během práce u klienta jsem si pro "Compare" operace ve Visual Studiu (TFS) nainstaloval WinMerge a po návratu od něj (u klienta jsem dělal na jeho počítači) jsem zjistil, že už se bez něj nedokáži obejít a že mi standardní komparátor ve VS nestačí. A že jsem zapomněl, jak WinMerge pro spolupráci s VS správně nakonfigurovat. A protože se mi to nechtělo zjišťovat, obrátil jsem se s důvěrou na Strýčka Googla a našel původní dva články, ze kterých jsem vycházel:Using winmerge as a merge tool in Visual Studio Team Suite a Using WinMerge with TFS.

Postup je jednoduchý:

  1. Nainstalovat WinMerge
  2. Menu Tools, položka Options, pak ve stromu Source Control, pod ním Visual Studio Team Foundation Server a na něm tlačítko Configure User Tools...
  3. Vybrat .exe WinMerge a správně zadat Arguments
    1. Compare: /x /e /ub /wl /dl %6 /dr %7 %1 %2
    2. Merge: /x /e /ub /wl /dl %6 /dr %7 %1 %2 %4

Má to jenom jednu chybu, a sice když je v nastavení WinMerge zašrtnuto "Allow only one instance tu run" a člověk se jej z VS pokusí otevřít ještě jednou, neotevřou se porovnávané soubory jako nová záložka v běžící instanci WinMerge, ale skončí to s podivnou chybou "The system cannot find the file specified". A vypadá to spíše na chybu VS, protože ten file (v TFSTemp), kterého se WinMerge domáhá, skutečně neexistuje.

Jeremy Miller : Cohesion And Coupling

Zajímavý článek od Jeremy Millera Cohesion And Coupling vyšel již před časem v MSDN Magazine.

Obsah

  • Decrease Coupling
  • Increase Cohesion
  • Eliminate Inappropriate Intimacy
  • The Law of Demeter
  • Tell, Don't Ask
  • Say It Once and Only Once
  • Wrapping Up 

Základní principy

  1. Keep things that have to change together as close together in the code as possible.
  2. Allow unrelated things in the code to change independently (also known as orthogonality).
  3. Minimize duplication in the code.

 

Solution Folders

Užitečnou pomůckou pro organizaci projektů (větší solution jich může obsahovat i řádově desítky) jsou solution folders - složky, které existují pouze v rámci solution a projekty v nich mohou být zařazeny bez ohledu na své fyzické umístění na disku. Velmi dobrý příklad je zde, jiný dobrý příklad nabízí např. Enterise Library, viz následující screenshoty:

 

 
Organizace na disku

 

 

 Organizace v Solution Exploreru

Mažeme na 116%

Nikdy nedefinovaný zákona zachování souborů by mohl znít: Lze smazat pouze tolik souborů, kolik jich bylo na filesystém uloženo. Total Commander jich však zvládne smazat mnohem více:

 

(Jistě, je to důsledek numerické chyby, nebo nějaké optimalizace, ale přeci jenom to člověka zarazí: co když opravdu začal mazat i něco víc, než co smazat měl?)

Špíček - zadávání velkých čísel nadvakrát

Problém, o kterém chci dnes mluvit, je úzce svázán s konkrétními technologiemi, takže asi nikomu trn z paty nevytrhne, nicméně jako inspirace a příklad toho, jakým způsobem se jednotlivé komponenty vzájemně ovlivňují a k jakým potížím to může vést, poslouží myslím celkem dobře.

 

Budiž chyba: Do prvku UI ButtonEdit (součást DevExpress), který je nabindován na dataset a má nastavenu numerickou maskou, nejde zadat více než 10 číslic jinak, než tak, že uživatel pole opustí a opět se do něj vrátí.

 

Po nikam nevedoucím laborování s nastavením masky a bindingu, následovaném chvilkou hledání na stránkách podpory výrobce je bezprostřední příčina a tedy i řešení na světě: The problem is that your TextEdit control is bound to an integer value. However, the integer type cannot accept more than 10 digits. The solution is to bind the control to a long value.

 

S touto znalostí je oprava již snadná: stačí při inicializaci (v InitializeComponent()) nastavit vlastnost EditValue controlu na hodnotu typu, který má větší rozsah než Int32, např: EditValue = 0L; nebo EditValue = new decimal(new int[] {0, 0, 0, 0}); (pozn. nelze použít EdiValue = 0m; protože s tímto zápisem se nevypořádá VS designer).

 

Tím se také vysvětluje, proč pomáhalo zadávání nadvakrát, tedy opustit kontrol a zase se do něj vrátit. Při opuštění se hodnota zapsala do datasetu, to vyvolalo změnovou událost, na kterou kontrol zareagoval načtením hodnoty z datového zdroje. A protože tato hodnota byla již typu Decimal, kontrol se tomu přizpůsobil a umožnil zadávání čísel přesahujících rozsah Int32.

 

Jenže stále zůstává otázka proč? Proč se kontrol chová, jako by byl nabindován na hodnotu typu Int32, když příslušný sloupec v datasetu je typu Decimal, respektive Int64? Tak na tuto otázku bohužel nemám lepší odpověď, než že to někdo naprogramoval tak, že se nezjišťuje typ vlastnosti, na kterou je kontrol nabindován, ale typ hodnoty, kterou binding vrátí. A je-li tato hodnota null (což u nově založené řádky v datasetu je), pak se kontrol chová, jako by byl bindován na defaultní Int32.

Rychlost volání delegátů

Cituji z (jinak velmi zajímavého, doporučuji k přečtení) článku The cost of enumerating in .NET:

Delegate dispatch still isn’t quite the speed of virtual method dispatch.  And delegates bound to static methods are actually slightly slower than those bound to instance methods, which is why you’ll notice a slight difference in the original “s” versus “i” measurements.  The reason is subtle.  There is a delegate dispatch stub that is meant to call the target method: when the delegate refers to an instance method, the ‘this’ reference pushed in EAX points to the delegate object when it is invoked and the stub can simply replace it with the target object and jump; for static methods, however, all of the arguments need to be “shifted” downward, because there is no ‘this’ reference to be passed and therefore the first actual argument to the static method must take the place of the current value in EAX.

Override virtuálních vlastností

Virtuální vlastnosti jsou definovány takto:

public class Base
{
  private bool isValid;

  public virtual bool IsValid
  {
    get { return this.isValid; }
    set { this.isValid = true; }
  }
}

Kód, který pro předefinování takto definované vlastnosti v potomkovi vygeneruje VS po "expanzi" klíčového slova override (a který jsem většinou slepě používal) je následující:

public class Derived : Base
{
  private bool hasInvalidItems = false;

  public override bool IsValid
  {
    get
    {
      
// & this.hasInvalidItems je implementace specifická pro třídu Derived

      return base.IsValid & this.hasInvalidItems; 
    }
    set
    {
      base.IsValid = value;
    }
  }
}

Jazyk C# však umožňuje předefinovat pouze getter/setter, přičemž pro nepředefinovaný accessor se použije implementace z předka:

public class Derived : Base
{
  private bool hasInvalidItems = false;

  public override bool IsValid
  {
    get
    {
      return base.IsValid & this.hasInvalidItems;
    }
  }

}

Musím kajícně přiznat, že přes letitou praxi jsem na tuto vlastnost C# přišel teprve nedávno. Přitom to není nic překvapivého, uvědomí-li si člověk, jak jsou vlastnosti realizovány na úrovni IL, je to zcela logické (tak jsem to ostatně také přišel - úvahou).

P.S. Jaký je překlad termínu override do češtiny? Nenapadá mne nic, co by nebylo matoucí a zavádějící.

Posted: 5. září 2008 16:42 by pbouda | 6 Comments
Vedeno pod: ,
Chyba 14001 při spuštění windows service

Byl jsem poněkud zaskočen tím, že se mi najednou nepodařilo spustit službu, která dříve bez problému chodila, a na níž se nezměnilo nic jiného, než že byla nově zkompilována po přechodu na VS2008. Chybová zpráva zněla:

System error 14001 has occurred.

This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.

Protože se v ní hovoří o "application configuration", začal jsem hledat příčinu v chybném .config souboru. Také jsem si ale povšiml, že k selhání služby dojde tak rychle po pokusu o spuštění, že velmi pravdepodobně není vůbec nataženo CLR a spuštěn .NET kód, takže .config není vůbec použit.

Začal jsem tedy pečlivěji pátrat v Event Logu, ve kterém jsem nakonec nalez několik záznamů ze zdroje SideBySide, které se týkají příslušné služby:

  • Syntax error in manifest or policy file "Service.exe.Config" on line 2. The manifest file root element must be assembly.
  • The application failed to launch because of an invalid manifest.
  • The CliView Application Server Host Service service failed to start due to the following error: This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.
  • A také poněkud matoucí Generate Activation Context failed for Service.exe. Reference error message: The operation completed successfully.

Z těchto záznamů jsem usoudil, že chyba je někde v manifestu aplikace, což bylo nepříjemné, protože je to pro mne španělská vesnice, a navíc s ním nikde vědomě nepracuji.

Nakonec jsem však řešení nalezl poměrně rychle ve Visual Studiu v Project Properties na záložce Application. Zde je ve spodní části sekce Resources, v ní volba Icon and Manifest a pod ní Manifest. Zde je možno vybrat mezi Embed manifest with default settings (defaultní volba) a Create application without a manifest. Stačí přepnout na Create application without a manifest, překompilovat a chodí to.

Mám však jisté pochybnosti o tom, že toto je skutečná příčina problémů, spíše si myslím, že by měl být způsob, jak vytvořit aplikaci s manifestem tak, aby mohla být zároveň spouštěna jako windows service.

Inicializéry (C# 3.0)

Jednou z novinek v jazyce C# 3.0 jsou inicializéry (anglicky initializers), typický zástupce rodu syntaktický cukr. Jedná o speciální konstrukci, která volitelně následuje po volání konstruktoru a ve které je umožněn implicitní přistup k nově vytvořené instanci a jejím datovým (pole, vlastnosti) členům. Zřejmější to bude na příkladu:

Mějme třídu Alfa:

public class Alfa
{
public int i;
public string s;
}

Její instanci je s pomocí inicializéru možno vytvořit takto:

Alfa a = new Alfa { i = 1, s = "a" };

což je zcela ekvivalentní zápisu: 

Alfa newAlfa = new Alfa();
newAlfa.i
= 1;
newAlfa.s
= "a";
Alfa a
= newAlfa;

(Poznámka: Závorky ve volání konstroktoru nejsou při použití inicializátoru povinné, takže Alfa a = new Alfa { i = 1, s = "a" }; a Alfa a = new Alfa () { i = 1, s = "a" }; jsou zcela rovnocenné zápisy.)

Z tohoto pohledu se tedy zdá, že inicializér nic nového nepřináší. Využití inicializéru je především v souvislosti s anonymní typy a LINQ. V následujícím příkladě (alfas je kolekce instancí třídy Alfa): 

var small = from a in alfas select new {Number = a.i};

představuje výraz new {Number = a.i} vytvoření instance anonymního typu. Kompilátor z inicializéru vyčte strukturu anonymního typu a především jména vlastností, která by ze standarní syntaxe konstruktoru nebylo vyčíst nedala.

Inicializace kolekcí

Větší použití zřejmě nalezne inicializér při vytváření kolekcí. Výše zmiňovanou kolekci alfas je s pomocí inicializéru možno vytvořit následovně:

 

List<Alfa> alfas = new List<Alfa>
{
new Alfa {i=1, s="one"},
new Alfa {i=2, s="two"},
new Alfa {i=3, s="three"},
};

což je ekvivalentní zápisu:

List<Alfa> alfas = new List<Alfa>();
Alfa a;
a
= new Alfa();
a.i
= 1;
a.s
= "one";
alfas.Add(a);
a
= new Alfa();
a.i
= 2;
a.s
= "two";
alfas.Add(a);
a
= new Alfa();
a.i
= 3;
a.s
= "three";
alfas.Add(a);

Který z obou zápisů je čitelnější je nabíledni.

Inicializace členských proměnných

Inicializéry umožňují též komplexní inicializaci členských proměnných třídy v deklaraci, což bylo zatím nutno řešit v explicitně konstruktoru. Opět ukáži na příkladu, protože tak to bude nejsrozumitelnější:

public class UsingInitializers
{
private List<Alfa> alfaList = new List<Alfa>
{
new Alfa {i=1, s="one"},
new Alfa {i=2, s="two"},
new Alfa {i=3, s="three"},
};
};

Vnořené inicializéry

Mějme kromě výše zmíněné třídy Alfa ještě třídu Omega:

public class Omega
{
public Alfa alfa;
}

Její instanci je s pomocí inicializéru možno vytvořit takto:

Omega w = new Omega { alfa = new Alfa { i = 3, s = "w" } };

Pozor, vnořený inicializér nevytváří instanci, kterou inicializuje. Proto je ve výše uvedeném příkladě třeba použít new Alfa(). Pokud by ovšem třída Omega byla definována následovně:

public class Omega2
{
public Alfa alfa = new Alfa();
}

Potom lze napsat jen:

Omega2 w2 = new Omega2 { alfa = { i = 3, s = "w" } };

Podobný zápis, ale s třídou Omega, tedy:

Omega w = new Omega { alfa = { i = 3, s = "w" } };

způsobí run-time exception.

 

(Pozn. Opravil jsem některé chyby, na které jsem byl upozorněn v komentářích).

Posted: 5. srpna 2008 16:18 by pbouda | 8 Comments
Vedeno pod: , ,
Fundamenty objektového paradigmatu

V diskusi pod článkem Můžeme se obejít bez dědičnosti vyvstala otázka, jaké že jsou vlastně základní pilíře OOP. Ukázalo se totiž, že každý za ně považuje něco jiného. Následujícím text je reakcí na tuto diskusi.

 

 

 

Základní vs. odvozené

Předně je třeba si ujasnit, jaký je rozdíl mezi pojmy primárními a sekundárními, čili základními a odvozenými. Odvozené (sekundární) pojmy je možno vyjádřit pomocí pojmů základních (primárních), zatímco naopak to neplatí. Jinak řečeno, existence sekundárních vlastností je bez existence primárních nemožná.

Bohužel, v případě OOP je realita taková, že primární a sekundární pojmy jsou často směšovány a zaměňovány, a nejednou to jde až tak daleko, že jsou sekundární pojmy ztotožňovány přímo s OOP samotným. Důvod tohoto nepochopení je nasnadě: sekundární pojmy se odrážejí přímo v objektových programovacích jazycích a bývají tím prvním (a pohříchu často jediným), s čím přijde nový adept OOP do styku.

Dělení pojmů na základní a odvozené je následující: Primární pojmy jsou identita, zapouzdření a skládání; sekundární jsou třída, dědění, polymorfismus.

V dalším textu proberu jednotlivé pojmy podrobněji a pokusím se vysvětlit, proč mnou uváděné rozdělení mezi pojmy primární a sekundární odpovídá výše uvednému.

Objektového paradigma

Výpočetní model

Možná poněkud netradičně začnu výpočetním modelem, který stojí ve středu programu vytvořeného podle paradigmatu OOP. Platí, že objektový program je systém, tedy množina prvků a vazeb mezi nimi (statická struktura), která vykazuje v čase identifikovatelné chování (dynamika). A právě tato dynamika, tedy v čase rozpoznatelné změny, je reprezentována výpočetním modelem, který je v OOP založen na posílání zpráv.

Jinými slovy, běh objektového programu spočívá v posílání zpráv mezi objekty a v jejich zpracováním na straně příjemce.

Je ovšem důležité mít na paměti, že toto platí pro konceptuální úroveň. Na fyzické úrovni, tedy v počítači, může být konkrétní realizace jiná, například volání procedur, skoky do podprogramů, přerušení.

Základní pojmy

Identita

Identita objektu znamená, že každé dva objekty jsou od sebe navzájem odlišitelné na základě prostého faktu své existence. Identita objektu nijak nezávisí na hodnotách vnitřních atributů objektu.

Toto je kardinální rozdíl například ve srovnání s relačními databázemi, ve kterých není z konceptuálního hlediska možno rozlišit dva záznamy, které mají stejné hodnoty všech atributů. Mimo jiné proto se do relačních tabulek zavádějí primární klíče, aby bylo možno přesně určit, který záznam je který. Identita objektu na konceptuální úrovni však není žádné číslo, není to primární klíč, je to fakt.

Identita je nezbytným předpokladem pro správnou funkci výpočetního modelu, protože pouze na jejím základě je možno přesně určit, kterému objektu je zpráva určena.

Zapouzdření

Každý objekt je vzhledem k svému okolí „černá skříňka“, která se navenek reprezentuje pouze svým protokolem – množinou zpráv, které je objekt schopen přijmout. Žádný z dalších prvků systému (objektů) nemá žádnou znalost o tom, co je uvnitř, jak je dotyčný objekt implementován.

Zapouzdření je klíčovým předpokladem pro zachování konzistence systému, protože vylučuje, aby data (tedy stav) objektu mohl neočekávaně či nesmyslně změnit jiný objekt. Zapouzdření přesně vymezuje odpovědnosti a jeho důsledkem je každý objekt může svá data považovat vždy za validní, protože nikdo jiný než on sám je nemůže změnit.

Zapouzdření představuje nejenom nástroj pro zajištění bezpečnosti a konzistence dat (potažmo celého systému, respektive programu), ale v podstatě vynucuje (opět na konceptuální úrovni) anonymitu klienta, čímž přispívá k lepší udržovatelnosti a škálovatelnosti programu.

Bez zapouzdření by nebylo možno jednoznačně určit, kde jsou hranice objektu, která data jsou jeho, a tedy za jaká data je objekt ještě odpovědný, a za jaká již ne.

Skládání

Skládání je vyjádřením HAS-A vztahu. Skládání znamená, že jeden objekt v sobě může obsahovat jiný objekt. Často se v této souvislosti hovoří o vztahu pán-sluha, protože typickou motivací pro vytvoření tohoto vztahu je, že pán (celek) pověřuje (deleguje) sluhu (část) vykonáním těch operací, které sám neumí. Navenek to však vypadá, jako kdyby vše vykonával sám pán (viz zapouzdření).

Skládání umožňuje vyvářet vazby mezi objekty, tedy definovat strukturu programu, a tím jednoduše a intuitivně směrovat zprávy k jejich příjemcům. Bez skládání by nebylo možno vytvořit navigační graf, ale program by sestával s chaotické změnit objektů, z níž by se příjemci zpráv museli složitě vybírat.

Je dobré rozlišovat dva typy skládání: silnou a slabou vazbu. Silná vazba (agregace) představuje takový vztah, kdy existence části bez existence celku nemá smysl. Slabá vazba (asociace) je vztah dvou objektů, které mohou existovat samostatně.

Odvozené pojmy

Význam odvozených pojmů tkví v tom, že usnadňují tvorbu programu, zlepšují udržovatelnost kódu, zvyšují kvalitu (a čitelnost) výsledného kódu. Odvozené pojmy tedy představují velmi silné a prospěšné nástroje pro úspěšnou tvorbu programu podle objektového paradigmatu, nejsou však pro vytvoření funkčního programu nezbytné, na rozdíl od pojmů základních.

Třída

Třída je šablona na instance. Třída určuje, jaké atributy (datové členy) a metody (funkční členy) bude objekt mít a umožňuje rychle a bezpečně vytvářet objekty, které mají stejný protokol, stejný počet a typ datových členů a stejné metody (jejichž kód je často sdílený na úrovni třídy), a liší se od sebe (není to však podmínkou) pouze v hodnotách svých datových členů.

Třída ovšem není totéž, co typ. Objekty, které reprezentují entity (není míněna entita v kontextu relačního paradigmatu), stejného typu, jsou rovněž stejného typu, přestože k jejich vytvoření nemusí být použita třída (šablona).

Třída není pro vytváření objektů nezbytná, každý objekt je vždy možno postavit „na zelené louce“, tedy vždy zas a znova specifikovat všechny jeho členy. Neexistence tříd neznamená nemožnost vytváření objektů, ovšem z důvodů značné redundance nebezpečně zvyšuje rizika spojená s tvorbou a údržbou programu.

Dědění

Dědění je vztah IS-A, tedy vztah mezi podobnými typy, z nichž jeden je spíše abstraktní (předek) a druhý spíše konkrétní (potomek).

Pro dědění platí obdobně jako pro třídu, že není nezbytné pro vytvoření programu, protože lze členy všech typů definovat vždy znova; samozřejmě s riziky, která jsou spojena s redundancí. Vzhledem k existenci zapouzdření je jedno, zda objekt získal některé své vlastnosti děděním, nebo je má nadefinovány znova, navenek to nelze nijak rozlišit, protože protokol (na kterém z pohledu výpočetního modelu jedině záleží) je v obou případech stejný.

Dědění lze velmi dobře nahradit skládáním tak, že „potomek“ skládá svého „předka“ a deleguje na něj ty operace, které jsou pro oba stejné, a sám vykonává pouze ty, ve kterých se liší.

Polymorfismus

Polymorfismem je obecně míněno, že stejná zpráva vyvolá různé reakce, které se mohou lišit podle typu příjemce (polymorfismus 1. druhu), ale i podle času (polymorfismus 2. druhu), či dokonce podle typu volajícího (polymorfismus 3. druhu).

Existence polymorfismu implicitně vyplývá z existence protokolu, výpočetního modelu a zapouzdření. Objekt zprávě (výpočetní model) buď rozumí, nebo nerozumí (protokol), pokud jí rozumí, je zcela na jeho odpovědnosti, jak jí zpracuje (zapouzdření).

Polymorfismus tedy není třeba definovat jako základní pojem, protože ze základních implicitně vyplývá.

Závěr

Jistá zmatečnost, která v ohledu dělní na základní a odvozené pojmy panuje, je podle mého přesvědčení způsobena tím, jak jsou navrženy (dominantně používané) programovací jazyky, které ve své většině neumožňují přístup k základním pojmům jinak, než prostřednictvím pojmů odvozených.

Všechny mně známé objektové programovací jazyky neumožňují vytvořit objekt jinak, než jako instanci třídy, přičemž každá třída vždy dědí (často implicitně) od jednoho triviálního předka (většinou třídy Object).

Mojí snahou bylo osvětlit rozdělení pojmů obecně užívaných v OOP na základní a odvozené a toto dělení i náležitě zdůvodnit. Obecný princip dělení je takový, že funkční (což ještě neznamená snadno realizovatelný a snadno udržovatelný) objektový program je možno vytvořit pouze na základně pojmů základních, naopak pojmy odvozené k vytvoření takového programy samy o sobě nestačí.

Více článků Další stránka »