Diskuze: OOP - Rozdělení proměnných třídy do "bloků" a zapouzdření

C# .NET .NET (C# a Visual Basic) OOP - Rozdělení proměnných třídy do "bloků" a zapouzdření American English version English version

Avatar
Xan95
Člen
Avatar
Xan95:

Ahoj, začínám programovat v C# (prošel jsem základní konstrokuce a oop tady na ITNetworku)
Nyní se pokouším udělat RPG postavu s opravdu velkým množstvím proměnných. Rád bych je rozdělil do samotných bloků na Vlastnosti, Schopnosti a Dovednosti.
Obrázek řekne víc než tisíc slov

Takže chci mít třídu Postava a v ní třídy Vlastnosti, Schopnosti a Dovednosti.

// Část že třídy Postava
public Vlastnosti Vlastnosti { get; private set; }
public Schopnosti Schopnosti { get; private set; }
public Dovednosti Dovednosti { get; private set; }

Pak mohu krásně přistupovat k jednotlivým složkám

// Mimo třídu
Postava postava = new Postava();
int drevcove = postava.Dovednosti.DrevcoveZbrane;

Problém je samozřejmě v zapouzdření. Chci aby jen postava mohla měnit svoje dovednosti a zde je kámen úrazu. Jaký je nejlepší způsob na zapoudření?

Napadlo mě vytvořit Interface IVlastnosti, ISchopnosti, IDovednosti a místo tříd vracet je. Mohlo by to vypadat následovně:

// Část že třídy Postava
private Dovednosti dovednosti;
public IDovednosti Dovednosti { get { return dovednosti; } }

Vše funguje fantasticky, přesně tak, jak jsem chtěl. Je zde však jeden problém. Interface jde přetypovat zpět na třídu, tudíž se dá zapoudření obejít.

// Mimo třídu
((Dovednosti)postava.Dovednosti).DrevcoveZbrane++;

Ještě mě napadlo vytvořit speciální třídu DovednostiInfo, kterou bude postava vracet. To už mi ale připadá příliš komplikované.

Jaký je tedy nejlepší způsob zapouzdření pro tento příklad?
Pozn: doufám že tímto rozdělením nějak neporušuju logiku OOP

 
Odpovědět 16. února 18:23
Avatar
Odpovídá na Xan95
Petr Čech (czubehead):

Normálně se tohle nepoužívá. Třeba takové kontrolky v WPF nebo WinForms mají také minimálně desítky vlastností a vše je prostě na 1 úrovni. Máš nějaký specifický důvod pro rozdělení vlastností do tříd?
Pokud bys to chtěl třeba z důvodu enumerace vlastností v jednotlivých "bloků" třeba jen zbraní, nejčistší by bylo udělat si vlastní atribut, který by tu skupinu specifikoval pomocí enum. Potom by sis udělal metodu nebo get-only property, která by pomocí reflexe mohla vrátit vlastnosti jen z dané skupiny. Jenže to bys asi musel udělat třídu navíc, která by reprezentovala jednotlivé vlastnosti, nejspíš generickou.
Pokud chceš kód, napiš mi. A použij prosím tlačítko odpovědět ;-)

Nahoru Odpovědět  +1 16. února 20:09
Why so serious? -Joker
Avatar
coells
Redaktor
Avatar
Odpovídá na Xan95
coells:

OOP je o způsobu návrhu aplikace, ne o bezpečnosti.
To znamená, že pokud máš instanci s rozhraním IDovednosti, tak to explicitně vyjadřuje, jak s danou instancí zacházet.
Dokonce i pokud bys nevěděl, jaká třída je ve skutečnosti instanciovaná, jsou v C# způsoby, jak změnit její interní stav.
Tím pádem si s tímhle nedělej hlavu a používej typy jako vyjádření způsobu komunikace s objektem.

A ohledně logiky OOP si nedělej hlavu, tvůj návrh na 100% neviděl OOP ani z dálky :-)
Návrh objektových aplikací musí začínat úplně jinak a vzniká na základě komunikace mezi objekty, ne na základě jejich vlastností.

 
Nahoru Odpovědět  +1 16. února 20:21
Avatar
Odpovídá na Xan95
sadlomaslox25:

v ramci C# stejne muzes pouzit reflexi a zmenit libovolny private field na jakekoli tride.

co se tyka prikladu tak staci abys tu tridu Dovednosti nastavil na private a vnoril do tridy Postava a mas to vyresene.

 
Nahoru Odpovědět  +1 16. února 20:44
Avatar
Odpovídá na sadlomaslox25
Petr Čech (czubehead):

Tady je to jedno, protože ten návrh je z hlediska návrhu špatně. Proto neexistují žádné fancy mechanismy, jak to udělat. Reflexe je sice zajímavá, ale nastavování privátních proměnných nepaří mezi best practices.

Nahoru Odpovědět 16. února 21:07
Why so serious? -Joker
Avatar
Xan95
Člen
Avatar
Odpovídá na Petr Čech (czubehead)
Xan95:

Děkuji všem za odpovědi.

Vlastnosti, Dovednosti a Schopnosti (V, D, S) jsem chtěl rozdělit do tříd především z toho důvodu, aby se k nim pohodlně přistupovalo. Po napsání slova postava. intellisense nenabízí milion proměnných ale pouze 3 (V, D, S) a po vybrání Dovedností zobrazí další např. JednorucniZbrane).

Petr Čech (czubehead) Něco o reflexích jsem našel až v pokročilém programování, já se zatím potloukám na nízké úrovni. Kdybys mi napsal nějaký příklad jak to zde využít, byl bych rád.

Enum se mi zdá pro tento příklad celkem vhodný. Napadlo mě to skladovat v privátní array kolekci a ven to pouštět přes metodu. Vypadá to celkem jednoduše a přistupuje se k tomu vcelku pohodlně.

enum Dovednosti { JednorucniZbrane, ObourucniZbrane, DrevcoveZbrane }; // atd

// Část že třídy Postava
private int[] dovednosti = new int[Enum.GetNames(typeof(Dovednosti)).Length];
public int VratDovednost(Dovednosti dovednost)
{
    return dovednosti[(int)dovednost];
}

// Mimo třídu
postava.VratDovednost(Dovednosti.DrevcoveZbrane);

coells To, že se dá nějak změnit private field na jákekoliv třídě jsem nevěděl. Děkuji za informaci.

 
Nahoru Odpovědět 17. února 19:33
Avatar
Xan95
Člen
Avatar
Xan95:

Asi to nebudu řešit. Nejjednodušší bude, když prostě ve třídě Postava inicializuju všechny proměnné jako property {get; private set} s předponou např. DovednostDrev­coveZbrane nebo SchopnostAtletika

 
Nahoru Odpovědět  +1 17. února 21:12
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 7 zpráv z 7.