Wzorce projektowe - zarządzanie wykonywaniem zadań.

Wzorce projektowe - zarządzanie wykonywaniem zadań.
Sparrow-hawk
  • Rejestracja:prawie 13 lat
  • Ostatnio:3 miesiące
  • Lokalizacja:Katowice
  • Postów:189
0

Napisałem taki kod:

Kopiuj
#include "stdafx.h"
#include <iostream>
#include <memory>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cassert>

class IOutput
{
public:
	virtual ~IOutput() {}

	virtual void write(const char *str) = 0;
};

class Display : public IOutput
{
public:
	void write(const char *str) override {std::cout << str << std::endl; };
};

class ISerial 
{
public:
	virtual ~ISerial() {};

	virtual void read() = 0;
	virtual int select() = 0;
};

class Serial : public ISerial 
{
public:
	Serial() { srand(static_cast<unsigned int>(time(NULL))); }

	void read() override { std::cout << "Serial reading data" << std::endl; }
	int select() override { return rand() % 2; }
};

class Manager : public std::enable_shared_from_this<Manager> {
private:
	std::unique_ptr<ISerial> iserial_;
	std::unique_ptr<IOutput> idisplay_;

	void doStaff1(void)
	{
		idisplay_->write("Do some staff 1.");
	}
	void doStaff2(void) 
	{
		idisplay_->write("Do some staff 2.");
	}
	void doStaff3(void)
	{
		idisplay_->write("Do some staff 3.");
	}
	void doStaff4(void)
	{
		idisplay_->write("Do some staff 1.");
	}

public:
	Manager(std::unique_ptr<ISerial> iserial, std::unique_ptr<IOutput> idisplay) : iserial_(std::move(iserial)), idisplay_(std::move(idisplay)) {}
	
	void doJob();
	void doComplex1()
	{
		doStaff3();
		doStaff4();
	}
	void doComplex2()
	{
		doStaff4();
		doStaff3();
	}
};

class IWorker 
{
private:
	
protected:
	std::shared_ptr<Manager> manager_;

public:
	IWorker(std::shared_ptr<Manager>manager) : manager_(manager) {}
	virtual ~IWorker() {}

	virtual void doIt() = 0;
	virtual const char* getName() = 0;

	static std::unique_ptr<IWorker> create(unsigned int type, std::shared_ptr<Manager>manager); 
};

class Subworker1 : public IWorker 
{
public:
	Subworker1(std::shared_ptr<Manager> manager) : IWorker(manager) {}

	void doIt() override { manager_->doComplex1(); }
	const char* getName() override { return "Subworker 1"; }
};

class Subworker2 : public IWorker
{
public:
	Subworker2(std::shared_ptr<Manager> manager) : IWorker(manager) {}

	void doIt() override { manager_->doComplex2();}
	const char* getName() override { return "Subworker 2"; }
};

std::unique_ptr<IWorker> IWorker::create(unsigned int type, std::shared_ptr<Manager>manager) 
{
	std::unique_ptr<IWorker> result;

	switch(type) 
	{
	case 0:
		result = std::unique_ptr<IWorker>(new Subworker1(manager));
		break;
	case 1:
		result = std::unique_ptr<IWorker>(new Subworker2(manager));
		break;
	}

	return result;
}


void Manager::doJob() 
{
	doStaff1();
	doStaff2();

	// Wybieram podwykonawcę (który będzie używał narzędzi menagara). Przed wykonaniem doStaff1, doStaff2 nie wiem kogo będę potrzebował.
	std::unique_ptr<IWorker> worker = IWorker::create(iserial_->select(), shared_from_this());

	worker->doIt();
	
	idisplay_->write(worker->getName());
}


int main(int argc, char * argv[])
{
	std::shared_ptr<Manager> man = std::shared_ptr<Manager>(new Manager(std::unique_ptr<ISerial>(new Serial), std::unique_ptr<IOutput>(new Display)));

	man->doJob();

	return 0;
}


A teraz napiszę co chciałem zrobić:

  • Obiekt klasy Manager ma zarządzać interfejsami;
  • W momencie utworzenia obiektu Manager nie wiemy jaki podwykonawca będzie nam potrzebny, ale potrzebny będzie max 1;
  • Liczba dostępnych rodzajów podwykonawców może ulec zmianie;
  • Podwykonawcy wykonają prace metodami menagera;
  • Chcę to osiągnąć przy możliwie najmniejszej liczbie klas;

Czyli podsumowując. Tworzę obiekt menagera, który po odebraniu informacji decyduje kogo zatrudnić, bo nie wie jak wykonywać pracę (ale dysponuje narzędziami).

edytowany 2x, ostatnio: Sparrow-hawk
kiyo
Ale jakie jest pytanie? Chcesz żeby sprawdzić kod?
Sparrow-hawk
Heh, zapomniałem napisać :]. Chcę zapytać, czy takie podejście do problemu ma sens, czy można zrobić to lepiej ;)
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

To o czym mówisz kojarzy mi się z fabryką abstrakcyjną. Poczytaj o tym.

Sparrow-hawk
  • Rejestracja:prawie 13 lat
  • Ostatnio:3 miesiące
  • Lokalizacja:Katowice
  • Postów:189
0

Wzorzec znam, chociaż tutaj poszedłem w nieco prostszą wersję metody fabrykującej. Generalnie, to co wstawiłem wyżej sprawuje się całkiem dobrze. Mogę modyfikować istniejących, lub modyfikować nowych worker'ów, a klasie Manager jest to obojętne :)

Jedyne co mnie tu zastanawiało to fakt pewnego zakleszczenia, bo Manager tworzy Workera, który odwołuje się do Managera (który go stworzył) :D

stryku
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:607
0

Subworkerzy nie powinni dostawać ptr na managera tylko jakiś interfejs. Teraz subworker1 może bez problemu wywołać sobie metodę Manager::doComplex2

Sparrow-hawk
  • Rejestracja:prawie 13 lat
  • Ostatnio:3 miesiące
  • Lokalizacja:Katowice
  • Postów:189
0

No, ale między innymi o to chodziło, aby mógł tak zrobić. Co tutaj zmieni interfejs do managera? Jedynie, to, że w przyszłości będzie można podmienić klasę Manager na inną, ale zakładam tutaj stałość klasy Manager.

fasadin
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
  • Postów:4882
0

A jakie ma byc zastosowanie tego manadzera? Do czego i dlaczego ma byc uzyty?

0
Sparrow-hawk napisał(a):

Jedyne co mnie tu zastanawiało to fakt pewnego zakleszczenia, bo Manager tworzy Workera, który odwołuje się do Managera (który go stworzył) :D

Więc nie masz pojęcia czemu tak to zakodowałeś - ergo nie wiesz co robisz.

Sparrow-hawk
  • Rejestracja:prawie 13 lat
  • Ostatnio:3 miesiące
  • Lokalizacja:Katowice
  • Postów:189
0

@fasadin Manager ma izolować workerów od reszty systemu. Ma dostarczać im jeden interfejs. Na tą chwilę zakładam sporą zmienność workerów, i praktycznie stałość obiektu Manager.

fasadin
ok, ale w jakim celu, jaki jest use case?
MO
Dyskusyjne założenie: "Podwykonawcy wykonają prace metodami menagera.." Jeśli ma wszelkie narzędzia do wykonania pracy to znaczy że ma 2 odpowiedzialności. Po pierwsze wybiera podwykonawcę a po drugie udostępnia narzędzia. W konsekwencji jeszcze na własne życzenie traci kontrolę kto i jak będzie tych narzędzi używał a może użyć bez zwracania uwagi na kolejność, atrybuty wywołania czy stan na początku. Pachnie metodą szablonową? Dla mnie tak. A to śliski wzorzec. Dodatkowo wiąże w dwie strony. Poza tym pomyśl logicznie, jaki manager zatrudnia kogoś by mu "zabierał kredki" :)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)