Rozbijanie problemu na wiele małych klas

0

Cześć,

chcę zaprojektować hierarchię klas dla zdarzeń myszki i klawiatury. Czyli ruszanie i klikanie. Pokażę co wymyśliłem dla myszki

#pragma once

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

    virtual void execute() = 0;
};


//InputEvent.hpp
#pragma once

#include <AbstractInputEvent.hpp>

#include <Windows.h>

class InputEvent : public AbstractInputEvent // tutaj będzie podział na windows i linux. To jest dla windowsa
{
protected:
    INPUT input;

public:
    InputEvent() {}
    virtual ~InputEvent() {}
};


//MouseEvent.hpp
#pragma once

#include <InputEvent.hpp>

class MouseEvent : public InputEvent // równiez windows
{
protected:
    MOUSEINPUT &mouseInput;

public:
    MouseEvent() :
        mouseInput( input.mi )
    {}
    virtual ~MouseEvent() {}
};


//MouseBtnDown.hpp
#pragma once

#include <MouseEvent.hpp>
#include <MouseButtonType.h>

class MouseBtnDown : public MouseEvent
{
private:
    MouseButtonType button;

public:
    MouseBtnDown( MouseButtonType button ) :
        button( button )
    {}
    ~MouseBtnDown() {}

    void execute()
    {
/*..*/
    }
};

Dla myszki będzie jeszcze MouseBtnUp i MouseMove. Można by jeszcze wstawić klasę MouseBtnEvent, po której by dziedziczyły MouseBtnDown i MouseBtnUp.

Tylko właśnie. Teraz pytanie. Czy to nie jest przesada rozbijać to wszystko na tyle małych klas?

Z góry dzięki za odp (:

0

Tak, to jest przesada i źle zaprojektowana aplikacja.
Eventy myszki to coś co dotyczy myszki, a nie różnych obiektów niezależnych.

Możesz mieć różne myszki i różnie mogą się zachowywać, ale teraz stworzyłeś klasy nie będące kompletnie niczym rzeczywistym. Właściwie zszedłeś do absurdu gdzie klasa to metoda u Ciebie.

0

Dzięki za odpowiedź (:

Może nie wysłowiłem się jasno i Ty mnie nie zrozumiałeś albo ja Ciebie.

Chcę zaprojektować klasy do symulowania myszki i klawiatury w systemie. Wybieramy rodzaj eventu myszy np. kliknięcie, wybieramy przycisk np. lewy. Czyli wywołam

MouseBtnDown (LEFT).execute()

. Ale rzeczywiście taki podział to przesada.

Więc czy zrobienie klasy np.

class MouseEventExecutor
{
public:
    static void execute( EventType, EventData );
};

Będzie lepszym pomysłem? Jeżeli i to odpada to co byś podpowiedział?

0

Moim zdaniem to jest czysta masakra. Masakracja. Spoko. Jak Ci się chce pisać tyle klas, to ok. Rozumiem, że niektóre odpowiedzialności można odpowiednio wydzielać do mniejszych klas, ale to jest przesada. Mało tego, moim zdaniem to nie jest w ogóle czytelne.

Spójrzmy na source kod SFML-a 2.3.1 - Nagłówek Event.hpp. Wyciąłem komentarze, pełny source kod SFML,a można znaleźć tutaj: http://www.sfml-dev.org/download/sfml/2.3.1/

class Event
{
public:

    struct SizeEvent
    {
        unsigned int width;  ///< New width, in pixels
        unsigned int height; ///< New height, in pixels
    };

    struct KeyEvent
    {
        Keyboard::Key code;    ///< Code of the key that has been pressed
        bool          alt;     ///< Is the Alt key pressed?
        bool          control; ///< Is the Control key pressed?
        bool          shift;   ///< Is the Shift key pressed?
        bool          system;  ///< Is the System key pressed?
    };
    struct TextEvent
    {
        Uint32 unicode; ///< UTF-32 Unicode value of the character
    };
    struct MouseMoveEvent
    {
        int x; ///< X position of the mouse pointer, relative to the left of the owner window
        int y; ///< Y position of the mouse pointer, relative to the top of the owner window
    };
    struct MouseButtonEvent
    {
        Mouse::Button button; ///< Code of the button that has been pressed
        int           x;      ///< X position of the mouse pointer, relative to the left of the owner window
        int           y;      ///< Y position of the mouse pointer, relative to the top of the owner window
    };
    struct MouseWheelEvent
    {
        int delta; ///< Number of ticks the wheel has moved (positive is up, negative is down)
        int x;     ///< X position of the mouse pointer, relative to the left of the owner window
        int y;     ///< Y position of the mouse pointer, relative to the top of the owner window
    };
    struct MouseWheelScrollEvent
    {
        Mouse::Wheel wheel; ///< Which wheel (for mice with multiple ones)
        float        delta; ///< Wheel offset (positive is up/left, negative is down/right). High-precision mice may use non-integral offsets.
        int          x;     ///< X position of the mouse pointer, relative to the left of the owner window
        int          y;     ///< Y position of the mouse pointer, relative to the top of the owner window
    };
    struct JoystickConnectEvent
    {
        unsigned int joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1])
    };
    struct JoystickMoveEvent
    {
        unsigned int   joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1])
        Joystick::Axis axis;       ///< Axis on which the joystick moved
        float          position;   ///< New position on the axis (in range [-100 .. 100])
    };
    struct JoystickButtonEvent
    {
        unsigned int joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1])
        unsigned int button;     ///< Index of the button that has been pressed (in range [0 .. Joystick::ButtonCount - 1])
    };
    struct TouchEvent
    {
        unsigned int finger; ///< Index of the finger in case of multi-touch events
        int x;               ///< X position of the touch, relative to the left of the owner window
        int y;               ///< Y position of the touch, relative to the top of the owner window
    };
    struct SensorEvent
    {
        Sensor::Type type; ///< Type of the sensor
        float x;           ///< Current value of the sensor on X axis
        float y;           ///< Current value of the sensor on Y axis
        float z;           ///< Current value of the sensor on Z axis
    };
    enum EventType
    {
        Closed,                 ///< The window requested to be closed (no data)
        Resized,                ///< The window was resized (data in event.size)
        LostFocus,              ///< The window lost the focus (no data)
        GainedFocus,            ///< The window gained the focus (no data)
        TextEntered,            ///< A character was entered (data in event.text)
        KeyPressed,             ///< A key was pressed (data in event.key)
        KeyReleased,            ///< A key was released (data in event.key)
        MouseWheelMoved,        ///< The mouse wheel was scrolled (data in event.mouseWheel) (deprecated)
        MouseWheelScrolled,     ///< The mouse wheel was scrolled (data in event.mouseWheelScroll)
        MouseButtonPressed,     ///< A mouse button was pressed (data in event.mouseButton)
        MouseButtonReleased,    ///< A mouse button was released (data in event.mouseButton)
        MouseMoved,             ///< The mouse cursor moved (data in event.mouseMove)
        MouseEntered,           ///< The mouse cursor entered the area of the window (no data)
        MouseLeft,              ///< The mouse cursor left the area of the window (no data)
        JoystickButtonPressed,  ///< A joystick button was pressed (data in event.joystickButton)
        JoystickButtonReleased, ///< A joystick button was released (data in event.joystickButton)
        JoystickMoved,          ///< The joystick moved along an axis (data in event.joystickMove)
        JoystickConnected,      ///< A joystick was connected (data in event.joystickConnect)
        JoystickDisconnected,   ///< A joystick was disconnected (data in event.joystickConnect)
        TouchBegan,             ///< A touch event began (data in event.touch)
        TouchMoved,             ///< A touch moved (data in event.touch)
        TouchEnded,             ///< A touch event ended (data in event.touch)
        SensorChanged,          ///< A sensor value changed (data in event.sensor)

        Count                   ///< Keep last -- the total number of event types
    };

    EventType type; ///< Type of the event

    union
    {
        SizeEvent             size;              ///< Size event parameters (Event::Resized)
        KeyEvent              key;               ///< Key event parameters (Event::KeyPressed, Event::KeyReleased)
        TextEvent             text;              ///< Text event parameters (Event::TextEntered)
        MouseMoveEvent        mouseMove;         ///< Mouse move event parameters (Event::MouseMoved)
        MouseButtonEvent      mouseButton;       ///< Mouse button event parameters (Event::MouseButtonPressed, Event::MouseButtonReleased)
        MouseWheelEvent       mouseWheel;        ///< Mouse wheel event parameters (Event::MouseWheelMoved) (deprecated)
        MouseWheelScrollEvent mouseWheelScroll;  ///< Mouse wheel event parameters (Event::MouseWheelScrolled)
        JoystickMoveEvent     joystickMove;      ///< Joystick move event parameters (Event::JoystickMoved)
        JoystickButtonEvent   joystickButton;    ///< Joystick button event parameters (Event::JoystickButtonPressed, Event::JoystickButtonReleased)
        JoystickConnectEvent  joystickConnect;   ///< Joystick (dis)connect event parameters (Event::JoystickConnected, Event::JoystickDisconnected)
        TouchEvent            touch;             ///< Touch events parameters (Event::TouchBegan, Event::TouchMoved, Event::TouchEnded)
        SensorEvent           sensor;            ///< Sensor event parameters (Event::SensorChanged)
    };
};

Nie ma tu żadnych niejasności. Event zawiera EventType który jest zwykłą enumeracją oznaczającą rodzaj eventu. Następnie W ZALEŻNOŚCI od rodzaju eventtypu są w evencie ustalane dodatkowe informacje - jeżeli jest to EventType::MouseButtonPressed, to mouseButton zróci ci informacje o pozycjach kliknięcia i rodzaju (lewy, prawy przycisk, środkowy... itp).

3

@Dawid90dd - u Ciebie z kolei nie ma ścisłego typowania i przez co łatwo o błędy. Wydaje mi się, że implementacja powinna zależeć od potrzeb i nie ma jednego słusznego sposobu na zrobienie czegokolwiek. Nim bardziej klasa spełnia wymagania i nim łatwiej się jej używa tym lepiej na potrzeby danego projektu.

@stryku - spójrz na problem który próbujesz rozwiązać od tyłu: zacznij pisać kod który chciałbyś zrobić ze swoją klasą i pisz bardzo ogólnie typu:

  • potrzebuje nagrać ruch myszki, do tego potrzebuję: pozycję myszki w funkcji czasu.

Z takiego czegoś piszesz klasy i samo wszystko wychodzi. Rozwiązywanie problemów od d**y strony trwa z reguły kilka razy dłużej i najczęściej kończy się nieskończonym projektem - pisz tylko to co potrzebujesz na danym etapie i skup się na rozwiązaniu problemu, a nie robisz bibliotekę do wszystkiego.

Tutaj masz genialny post od @msm na temat przekomplikowania problemów: http://4programmers.net/Forum/Inzynieria_oprogramowania/201041-o_utrudnianiu_sobie_zycia_w_c++_za_pomoca_wektorow_metod_i_szablonow

0

Dziękuję za odpowiedzi (:

@krwq zastanowię się nad tym

0

Tak naprawdę nie ważne jak Ci to konkretnie wyjdzie. Ważne, żeby obrazowało się to tak

-----------------------------------------------------------------------
Platform Abstraction | Collect and forward OS input events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
    Input Manager    | Translate OS input events into logical events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
Character Controller | React to logical events and affect game play
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
      Game Logic     | React to player actions and provides feedback
-----------------------------------------------------------------------
0

@spartanPAGE więc widzę, ze nie wiecie dokładnie co chcę zrobić. Spróbuję to wytłumaczyć

To nie jest gra. Jest to program, który dostaję xmla, w uproszczeniu np.
<event>
<type>MOUSE_LEFT_DOWN</type>
</event>

albo
<event>
<type>WRITE_TEXT</type>
<data>Text to write</data>
</event>

i on na podstawie takiego xmla wie co ma robić i to robi.

I tak dziękuję za odowiedzi. Post @msm przeczytam nie raz pewnie ;)

1

No widzisz; W takim razie jest jedna najważniejsza rzecz - najwyższa forma abstrakcji Ciebie musi być na tyle jednolita, by dało się ją trzymać w homogenicznym kontenerze.

0

Mam takie coś :) po poście @Pijany Samiec próbowałem to uprościć, ale i tak wróciłem do mniej więcej tego co było w pierwszym poście (nie tego samego). To o czym mówisz to zostawiłem(nie wiem czy nazwa taka sama jest)

#pragma once
 
class AbstractInputEvent
{
public:
    AbstractInputEvent() {}
    virtual ~AbstractInputEvent() {}
 
    virtual void execute() = 0;
};

I hula

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