Kompozitní objekt obsahující entitu i služby
- artemevsin
- Člen | 61
Ahoj,
dotaz nesouvisí přímo s Nette, ale spíše všeobecně s návrhem.
Nicméně na stackoverflow jsem se názoru nedočkal, tak prosím o radu
zkušenějších zde.
Mám několik malých knihoven, které řeší konkrétní věci – třeba ImagesManager, TagsManager apod. Pak mám také malé knihovny typu MachinesManager, které spravují jednotlivé stroje a jejich parametry. Všechny knihovny vytváří entity (např. Image), které mají přiřazené vygenerovné UUID, pomoci kterého spolu komunikují:
<?php
interface IUuidUser {
public function getUuid();
}
/**
* @return Image[]
*/
class ImagesManager {
public function findImages(IUuidUser $user) {
return $this->dataSource->findByUuid($user->getUuid());
}
}
class Machine implements IUuidUser {
}
// použití
class TestPresenter {
public function test()
{
$machine = new Machine();
$machineImages = $this->imageManager->findImages($machine);
}
}
?>
Jelikož vím, že stroje mohou mít obrázky a např. tagy, tak bych chtěl entitu Machine zaobalit do kompozitní třídy MachineCompositeObject, která dostane v konstruktoru všechny potřebné služby a budu tak moct vytvořit hezčí rozhraní pro práci s Machine.
<?php
class MachineCompositeObject {
private $machine;
private $imagesManager;
private $tagsManager;
public function __construct(Machine $machine, ImagesManager $imagesManager, TagsManager $tagsManager)
{
$this->machine = $machine;
$this->imagesManager = $imagesManager;
$this->tagsManager = $tagsManager;
}
public function getName()
{
return $this->machine->getName();
}
public function getImages()
{
return $this->imagesManager->findImages($this->machine);
}
public function getTags()
{
return $this->tagsManager->findTags($this->machine);
}
}
?>
Je to vlastně taková fasáda, která se vytváří ale pro každou entitu.
Je podle vás ten návrh takto v pořádku?
Budu rád za jakékoliv názory :)
- artemevsin
- Člen | 61
S továrničkou počítám.
Teď mě ještě napadlo, že možná by bylo lepší vytvořit čistě službu MachineService do které zapouzdřím potřebné služby…
Jestli to není čistší řešení a nebudou se mi zbytečně vytvářet nové instance pro každý stroj
<?php
class MachineService {
public function __construct(ImagesManager $imagesManager, TagsManager $tagsManager)
{
$this->imagesManager = $imagesManager;
$this->tagsManager = $tagsManager;
}
public function getImages(Machine $machine)
{
return $this->imagesManager->findImages($machine);
}
}
?>
- GEpic
- Člen | 566
Podle mě by měl být jakýkoliv Manager standalone a poté se ho kdekoliv dotazovat. Než si veškeré managery předávat do mašinky. Co když zjistíš že budeš chtít některého z managerů použít i mimo mašinku, tak i tak si ho budeš muset injectnout někde zvlášť a pak to celé dle mého postrádá smysl.
Přijde mi to jako fitko – že se někteří snaží cvičit super efektivní cviky z NASA, přitom jednoduché věci prostě fungují. #nohate :D
Editoval GEpic (30. 8. 2016 10:32)
- artemevsin
- Člen | 61
jde mi především o to, že z pohledu byznys logiky aplikace neexistuje zvlášť stroj a zvlášť obrázek, ale existuje stroj, který má obrázky. Takže z tohoto důvodu jsem to chtěl takto zapouzdřit.
Ale čim víc nad tím přemýšlím, tím víc mi to přijde jako zbytečný
overhead, přesně jak píšete :D
Takže vás poslechnu a nechám to tak jak to je :)
- Oli
- Člen | 1215
jde mi především o to, že z pohledu byznys logiky aplikace neexistuje zvlášť stroj a zvlášť obrázek, ale existuje stroj, který má obrázky. Takže z tohoto důvodu jsem to chtěl takto zapouzdřit.
Tak to jednoduše vynutíš tím, že pokud:
- Existuje pouze stroj s obrázkem – tak do konstruktoru entity stroj si předáš obrázek (bez něj nepůjde stroj vytvořit)
- Může existovat i stroj bez obrázku (ale ne obrázek bez stroje) – Do konstruktoru obrázku si předáš stroj (bez stroje nepůjde obrázek vytvořit)
- Může existovat stroj i obrázek zvlášť – normální setry nebo jakkoli jinak. Prostě nevynucuješ jednu entitu druhou v konstruktoru…
- artemevsin
- Člen | 61
2. Může existovat i stroj bez obrázku (ale ne obrázek bez stroje) – Do konstruktoru obrázku si předáš stroj (bez stroje nepůjde obrázek vytvořit)
Do konstruktoru obrázku se předává objekt implementující IUuidUser, který má metodu getUuid() (což může být stroj, uživatel, firma, prostě cokoliv co má UUID). Takže obrázek ví jen to, že patří nějakému UUID, ale neví, co to je.
Takže pokud chci získat obrázky, musím tomu ImagesManager předat entitu, pro kterou chci vytáhnout obrázky.
Stroj jako takový neví o existenci nějakých obrázků – tj. spravují jen to svoje. Například knihovna, která se stará o stroje, má nějakou interní logiku toho, co všechno ten stroj má, jaké může mít parametry apod.
Knihovna, která spravuje obrázky, stará se jen o ty obrázky, tj. ukládá je do úložiště (přes injectnujtý IStorage), upravuje (opět přes injectnutý IImageProcessor) apod. Díky tomu jsou jednotlivé knihovny znovupoužitelné.
A právě ta vyšší vrstva aplikace by ty jednotlivé knihovny měla spojit, protože až teprve ona ví, že stroj může být s obrázkem. Tudíž mi z toho tak nějak vyplývá, že by se měla vytvořit jakási proxy entita, která zapouzdří tyhle vazby a bude odpovídat byznys logice – tj. že stroj může mít obrázek. Ale pravděpodobně by to jen zbytečně zkomplikovalo vývoj…
- newPOPE
- Člen | 648
Myslel som nieco taketo
class Machine {
use ImageAwareTrait;
}
trait ImageAwareTrait {
public function getImages() {
return $this->imagesManager->findImages($this->getUuid());
}
}
Akurat je trochu problem tam dodat ten imagesManager
:). Ale
keby si to napisal nejak takto:
trait ImageAwareTrait {
/** @var IImagesManager */
protected $imagesManager;
public function getImages() {
if($this->imagesManager) {
return $this->imagesManager->findImages($this->getUuid());
}
}
}
Tak by to mohlo fungovat „automaticky“ stacilo by len injektnut danemu
objektu nejaku instanciu IImagesManager
.
je to z hlavy cize to moze nefungovat, ide o myslienku skladania.
Editoval newPOPE (30. 8. 2016 15:08)
- artemevsin
- Člen | 61
jak tak koukám, tak je to skoro stejné jako ten kompozitní objekt :) jen ty jednotlivé funkce jsou zabalené do traity. Ale tomu objektu Machine bych stejně musel předat všechny ty managery…