Jak zaprojektować klasy

0

Witam.

Poniżej naszkicowałem schemat projektu swojego programu.
Chodzi o to że mam klasę bazową Figura i klasy, które z niej dziedziczą.
Używam funkcji wirtualnych i korzystam z dobrodziejstw polimorfizmu.
Do programu należy jednak dodać nową funkcjonalność, trzeba logować to co się dzieje z obiektem podczas rysowania.
Gdyby sprawa ograniczała się do jednej funkcji logującej, dodał bym ją do każdej klasy i po problemie.
Problem w tym że tych funkcji logujących mam na chwilę obecną już pięć.
Więc aż się prosi zbudować nową klasę Logger i tam umieścić odpowiedni kod obsługujący logowanie.
Nie wiem tylko jak to zrobić ażeby przy okazji nadal korzystać z polimorfizmu??
Nie chciał bym w tej nowej klasie Logger stosować instrukcji if() switch()... w zależności od tego z jakim obiektem będzie ona miała do czynienia.
Proszę o jakieś sugestie jak ten problem rozwiązać??

 
class Figura
{
 public:
	virtual void rysuj (void) { }
};

class Elipsa : public Figura
{
 public:
	 void rysuj (void){ printf ("Rysuj elipse\n") }
};

class Kwadrat : public Figura
{
 public:
	 void rysuj (void){ printf ("Rysuj kwadrat\n") }
};

int main (void)
{
 Figura *wskF=new Elipsa();

 wskF->rysuj(); //rysuje elipse
}

Pozdrawiam.

0

Logger, sam w sobie nie skomplikowany - w tym wypadku otoczka dla cout

class Logger{
private:
	ostream &m_oss;
public:
	Logger(ostream &oss) : m_oss(oss){}
	void log(const string &str){
		m_oss << str << endl;
	}
};

Chcemy rysować i rejestrować figurę, więc tworzymy proste inferfejsy

struct IDrawable{
	virtual void draw() = 0;
};

struct ILogable{
	virtual Logger *logger() const = 0;
	virtual void logger(Logger *) = 0;
};

Teraz nasza abstrakcyjna figura. Każda figura ma zwracać informacje o tym, czym jest.

class Shape : IDrawable{
protected:
	virtual string info() = 0;
};

Ponieważ figura ma być logowana, specjalizujemy ją w tym.

class RegisteredShape : public Shape, ILogable{
protected:
	Logger *m_logger;
public:
	Logger *logger() const{ return m_logger; }
	void logger(Logger *l){ m_logger = l; }
	void draw(){
		m_logger->log("drawing " + info());
	}
};

Do testów tworzymy, dwie realne, rejestrowalne figury.

class RegRectangle : public RegisteredShape{
protected:
	string info() { return "Rectangle"; }
};

class RegCircle : public RegisteredShape{
protected:
	string info() { return "Circle"; }
};

Całość posolić, popieprzyć i wymieszać.

Logger l(cout);
array<RegisteredShape *, 2> shapes = {
	new RegRectangle(),
	new RegCircle()
};
	
for(auto *shape : shapes){
	shape->logger(&l);
	shape->draw();
}
stdout napisał(a)

drawing Rectangle
drawing Circle

http://ideone.com/hHuS2S

1

ja zdecydowanie proponuję osobne działanie loggera, i includowanie go w plikach cpp gdzie jest potrzebny, tak jak to jest wytłumaczone tutaj http://www.drdobbs.com/cpp/logging-in-c/201804215

0

A nie lepiej zamiast dziedziczenia zastosować tutaj tzw dependency injection? To znaczy w klasach które maja być logowane trzymać referencje na obiekt Logger i inicjalizować ta referencje na liście inicjalizacyjnej? Odpada dziedziczenie a i klasa Logger jest tylko jedna dla całej aplikacji?

1 użytkowników online, w tym zalogowanych: 0, gości: 1