Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:

Soutěž

Sponzorem soutěže je:

IDIF

 

Kde se koná výstava fotografií Luďka Vojtěchovského?

V dnešní soutěži hrajeme o:



Výběr návrhového vzoru

Seznam témat     Nová odpověď

Přihlásit se     Registrace     Zapomenuté heslo

RE: Vyber navrhoveho vzoru

Autor: RSTEIN

15:44:06 09.03.2011

Ano, to je jeden z důvodů, na které jsem čekal, jestli je nezmíní wotaen a
raději jsem nenapovídal.:)
Potom by to vedlo na použití vícero temporálních vlastností, nebo skutečně
vytvoření snapshotu celého objektu Uživatel. I kdyby se ale tento požadavek
objevil dodatečně, současný systémový design tím moc trpět nebude. YAGNI v
praxi že:)



Zdravim
Rene Stein
http://blog.renestein.net
twitter: http://twitter.com/renestein


Příspěvek zaslán emailem

Citovat příspěvek

 

RE: Vyber navrhoveho vzoru

Autor: ivanpagac

15:36:51 09.03.2011

Mna napada pouzitie historie len v tomto pripade:
Agent zalozi zmluvu, o 2 roky sa vyda (teda je to agentka :)) a zmeni si priezvisko. Ja ale napriklad by som chcel vidiet, ake udaje boli na zmluve vtedy. Riesil by som to cez nejaky service pre usera, pripadne v userovi metodu GetSnapshot. Samozrejme to zalezi na povahe aplikacie, ak sa to potrebovat nebude tak je zbytocne do toho ist a stazovat si dizajn...
Ivan Pagáč-----Original Message-----
From: wotaen
Sent: 09.03.2011, 15:25
To: wwwdiskuze@builder.cz
Subject: Re: Vyber navrhoveho vzoru [160|3316093]




Máte naprostou pravdu, v tomto případě je váš návrh mnohem jednodušší.

ohledně "killer" důvodu, na Şádný jsem zatím nepřišel. Historii evidovat třeba bude, ale obyčejný log postačí.
DĂ­ky
--
Autor: wotaen
Forum: OOP a UML
Odkaz: http://forum.builder.cz/read.php?160,3316093,3316291#msg-3316291


Příspěvek zaslán emailem

Citovat příspěvek

 

Re: Výběr návrhového vzoru

Autor: wotaen

15:25:45 09.03.2011

Máte naprostou pravdu, v tomto případě je váš návrh mnohem jednodušší.

ohledně "killer" důvodu, na žádný jsem zatím nepřišel. Historii evidovat třeba bude, ale obyčejný log postačí.
Díky

Citovat příspěvek

 

RE: Vyber navrhoveho vzoru

Autor: RSTEIN

13:08:38 08.03.2011

Dobrý den,

1) I v mém návrhu je je tvůrce (creator) vlastnost kontraktu a současně má
kontrakt vlastnost ProvisionLevel. Berte to tak, že u kontraktu si chci
skuečně přečíst, kdo jej založil, a za vlastnost asociace Creator-Contract
můžeme považovat Level platný v době vytvoření kontraktu.

2) I u mě má User (agent u vás?) vlastnost ProvisionLevel - míněna v
současné době platná provizní úroveň a objekt ProvisionLevel žádný odkaz na
objekt User nemá.

3) Creator-ProvisionLevel vypovídá o současné úrovni provizí objektu
UŽIVATEL, Contract-ProvisionLevel o úrovni provize, která má smysl jen pro
konkrétní kontrakt.

Vlastnost Contract->Creator->ProvisionLevel nemůže pro JEDEN objekt uživatel
u VÍCERO smluv vracet RůZNÉ provizní stupně. Přesněji řečeno, technicky se
to zpatlat dá, ale je to naprosto nevhodné a neintuitivní řešení. Pokud vám
vadí název, můžete u třídy User vlastnost ProvisionLevel přejmenovat na
CurrentProvisionLevel - Contract->Creator->CurrentProvisionLevel

Můžete samozřejmě z User.ProvisionLevel udělat temporální vlastnost.
To znamená, že zavoláte na User.GetProvisionLevel(Contract.CreateDate), nebo
podobnou službu zapouzdříte v ContractServices, a temporální vlastnost vám
vrátí provizní stupeň platný k danému datu.

Uvědomte si ale:
1) Komplikujete řešení tím, že částečně zavádíte evidenci historie a z
vašich požadavků zatím nevyplynul žádný "killer" důvod, proč se historií
zabývat.
2) Jestliže je u Contractu provizní úroveň dána v době vzniku kontraktu, je
fixní a nezávisí na dalších vstupních parametrech, je zřejmé i pro uživatele
(programátora) business modelu, že vlastnost ProvisionLevel představuje
provizní stupeň používaný při výpočtu provize a že nemusí být shodný (proč
také, když mě teď zajímají informace o Contract?) s
Creator.(Current)ProvisionLevel.


Zdravim
Rene Stein
http://blog.renestein.net
twitter: http://twitter.com/renestein


Příspěvek zaslán emailem

Citovat příspěvek

 

Re: Výběr návrhového vzoru

Autor: wotaen

12:47:11 08.03.2011

Snad jsem to z toho zdrojaku pochopil dobre...obecny princip je v tom, že v mém návrhu je tvůrce jako property kontraktu. Ve vašem případě je přímo level property kontraktu.
V obou případech počítám, že level bude property agenta a level jako takový nebude mít link na agenta (asi jednosměrná agregace)
Nápad se mi líbí, ale mám s tím jeden problém...

Může nastat případ, kdy atribut creator->level a atribut level jsou u kontraktu různé, což se mi moc nelíbí. Přijde mi čistější, když creator->level vrátí správný level, který v době asociace měl.

Citovat příspěvek

 

Re: Výběr návrhového vzoru

Autor: Rene Stein

10:57:32 08.03.2011

Dobry den,
Snad jsem vas dobře pochopil. Abychom měli zaklad pro případnou další debatu, napsal jsem kod.
Vychazim z toho, ze dokud nepotrebuje zadne specialitky, at uz jsou to navrhove vzory nebo nejake specializovane reseni historie, je lepsi mit reseni bez nich. Pokud specialitky potrebujete, na tomto systémovém designu v kodu mi ukazte proc.
Kod je v C#, nevim, v cem pisete vy, ale da se jednoduse preklopi do jakehokoli jazyka, protoze jsem se snazil unikatni rysy C# moc nepouzivat. Kod jsem dal take na Github, kde ho uvidite alespoň trochu lépe formátovaný - http://jdem.cz/kww33

Takze u me:

Trida USer - jedine, co je zajimave, ze ma odkaz na AKTUALNI provizni uroven (ProvizionLevel) - jak vidite, zadnou historii nedrzim.

class User
{
private ProvisionLevel m_level;
public User(int id, ProvisionLevel level)
{
if (id < 0)
{
throw new ArgumentOutOfRangeException("id");
}

testLevel(level);
m_level = level;
Id = id;

}


public int Id
{
get;
private set;
}

public string Name
{
get;
set;
}

public ProvisionLevel Level
{
get
{
return m_level;
}
set
{

testLevel(value);
m_level = value;
}
}

private void testLevel(ProvisionLevel level)
{
if (level == null)
{
throw new ArgumentNullException("level");
}
}

}




Trida ProvisionLevel - obyčejný čísleník, který nese procentuální slevu.

class ProvisionLevel
{
public ProvisionLevel(int id, double percent)
{
if (id < 0)
{
throw new ArgumentOutOfRangeException("id");
}

if (percent <= 0d)
{
throw new ArgumentOutOfRangeException("percent");
}

Id = id;
Percent = percent;
}


public int Id
{
get;
private set;
}

public double Percent
{

get;
private set;
}
}


Contract - třída repreyentující smlouvu. Jak vidíte, SAMA TŘÍDA Contract si nese odkaz na provizní úroveň, se kterou byla vytvořena. Metoda pro výpočet provize CalculateProvision je prozatím umístěna ve třídě Contract, ale poku je jeji logika složitější, můžeme zavést miniobjekty Strategie, rozšířit služby v IContractService (viz dále).

class Contract
{
//Nebo je Amount decimal, protože jde o monetární operace - lze také vvytvořit typ Money
public Contract(int id, User creator, ProvisionLevel level, double amount)
{
if (id < 0)
{
throw new ArgumentOutOfRangeException("id");
}

if (creator == null)
{
throw new ArgumentNullException("creator");
}

if (level == null)
{
throw new ArgumentNullException("level");
}

if (amount <= 0d)
{
throw new ArgumentException("amount");
}

Id = id;
Creator = creator;
Amount = amount;
ProvisionLevel = level;
}

public int Id
{
get;
private set;
}

public ProvisionLevel ProvisionLevel
{
get;
private set;
}

public User Creator
{
get;
private set;
}

public double Amount
{
get;
set;
}

//Nebo pokud je logika složitější, delegovat na ContractService, objekty Strategy apod.
public virtual double CalculateProvision()
{
checked
{
return (Amount / 100d) * ProvisionLevel.Percent;
}
}
}


Za vytvoření třídy Contract odpovídá ale business služba ContractService - do této třídy mohu skrýt logiku, která souvisí s vytvořením nové smlouvy, aniž bych třídy User a Contract zatěžoval scénářem pro vytvoření smlouvy, na kterém participuje více tříd a jde pravděpodobně o scénář, který nepatří jen do třídy User ani Contract

interface IContractService
{
Contract CreateNewContract(User user, double amount);
}

lass ContractService : Provisions_Builder.IContractService
{
private SimpleSequenceGenerator m_simpleSequenceGenerator;
public ContractService()
{
m_simpleSequenceGenerator = new SimpleSequenceGenerator(0, Int32.MaxValue);
}

public Contract CreateNewContract(User user, double amount)
{


if (user == null)
{
throw new ArgumentNullException("user");
}

return new Contract(m_simpleSequenceGenerator.GetNextNumber(), user, user.Level, amount);
}


Zde je jednoduchý scénář, který ukazuje výpočet provizí u smluv před změnou i po změně provizního stupně uživatele.

class Program
{
public static readonly double DEFAULT_PROVISION = 6;
public static readonly double VIP_PROVISION = 10;
static void Main(string[] args)
{
SimpleSequenceGenerator generator = new SimpleSequenceGenerator(0, Int32.MaxValue);
var defaultProvisionLevel = new ProvisionLevel(generator.GetNextNumber(), DEFAULT_PROVISION);
User user = new User(generator.GetNextNumber(), defaultProvisionLevel)
{
Name = "Josef Novak"
};

//Nebo a lépe DI kontajner - Contaniner.Resolve
IContractService contractService = new ContractService();
Contract standardContract = contractService.CreateNewContract(user, 100d);
Console.WriteLine("Standardní kontrakt provize {0}", standardContract.CalculateProvision());
//Změníme úroveň uživatele
user.Level = new ProvisionLevel(generator.GetNextNumber(), 20);
Contract vipContract = contractService.CreateNewContract(user, 100d);
Console.WriteLine("Standardní kontrakt - provize po změně úrovně uživatele {0}", standardContract.CalculateProvision());
Console.WriteLine("VIP kontrakt provize {0}", vipContract.CalculateProvision());

Console.ReadLine();
}
}


Pro úplnost sem dávám i výpis jednoduché třídy pro generování Id objektů, protože objekty nejsou perzistentní.

internal class SimpleSequenceGenerator
{
#region private variables
private object m_lockRoot = new Object();
private int m_start;
private int m_end;
private int m_current;

#endregion private variables
#region constructors
public SimpleSequenceGenerator(int start, int end)
{
if (start > end)
{
throw new ArgumentException();
}
m_current = m_start = start;
m_end = end;
}
#endregion constructors
public int GetNextNumber()
{
lock (m_lockRoot)
{
return getNumber();
}
}

private int getNumber()
{
if (m_current == m_end)
{
m_current = m_start;
}
return ++m_current;
}
}

Citovat příspěvek

 

Výběr návrhového vzoru

Autor: wotaen

7:19:42 08.03.2011

Ahoj,

navrhuji systém, který bude obsahovat jeden typ problému na více místech a řeším, zda neexistuje nějaká kombinace návrhových vzorů, kterou bych mohl použít...o co jde.
Uživatel má určitou úroveň. Ta je definována jako procento. Uživatel vytváří smlouvy a základě hodnoty smlouvy a jeho úrovně se spočítá jeho provize.
Systém musí udržovat historii změn. Tj uživatel je na úrovni A a vytvoří smlouvy 1,2,3. Pak se posune na úroveň B (s jinými procenty) a vytvoří dalších X smluv. Systém musí správně spočítat provizi za 1,2,3 (byl na úrovni A) a X (už na úrovni B).
Budou dvě třídy Uživatel a Smlouva. Smlouva bude mít atribut creator typu Uživatel.
Napadlo mě u třídy Uživatel mít schované stavy v historii (úroveň A a úroveň B) a ukazatel na aktuální stav. Zároveň by třída Uživatel měla metodu "selectInstance" která by vybrala správný stav v historii (asi na základě parametru Smlouva). Když pak vytvořím smlouvu, předám jí "creatora" skrze metodu selectInstance.
Co říkáte na moje řešení, šlo by to dělat jinak, elegantněji?

Díky, Michal

Citovat příspěvek

 

 

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: