methodenkapselung



  • ich suche nach einer möglichkeit das der user meiner klasse unabhängig von seiner nutzung ein objekt verwenden kann ohne das ich alle member mittels getter offen lege.
    einfach bespiel wäre eine methode eines rechteckts zum zeichnen.
    mögliche implementierungen zum wären zb: winapi, directx, qt, asci usw usw.
    folgende ideen hatte ich schon:

    template<
    	class T_>
    class foo
    {
    	public:
    		typedef T_		value_type;
    
    		foo(const T_& t = 0) : mt(t) { }
    
    		void set_callback(boost::function<void (const T_& t)> func)
    			{ m_Callback = func; }
    
    		void execute() const
    		{
    			if(m_Callback)
    				m_Callback(mt);
    		}
    
    	private:
    		T_ 										mt;
    		boost::function<void (const T_& t)>		m_Callback;
    };
    
    template<
    	class T_>
    void bar(const T_& t) { std::cout << t << std::endl; }
    
    // usage:
    // f.set_callback(bar<foo_type::value_type>);
    // f.execute();
    

    grosser nachteil daran ist die objektgrösse ansteigt und falls das rechteck
    in eine datei gespeichert wird erhöht dieses natürlich merklich die dateigrösse
    und der callbackmember ist beim auslesen natürlich nutzlos.

    zweite möglichkeit wäre eine methode zu deklarieren aber die definition
    dem user der klasse zu überlassen. ich denke das dieses eher unüblich ist,
    zumindest keine ich kein beispiel. finde dieses aber eine elegante lösung

    template<
    	class T_>
    class foo
    {
    	public:
    		void execute() const;
    
    	private:
    		T_ 	mt;
    };
    // usercode
    template<class T_> void foo<T_>::execute() const { std::cout << mt << std::endl; }
    

    dritte möglichkeit natürlich wären policys

    template<
    	class T_>
    class bar
    {
    	public:
    		bar(const T_& t) : mt(t) { }
    
    		void execute() const { std::cout << mt << std::endl; }
    
    	protected:
    		T_ 	mt;
    };
    
    template<
    	class T_,
    	template <class> class ExecutePolicy_>
    class foo : public ExecutePolicy_<T_>
    {
    	public:
    		typedef T_		value_type;
    
    		foo(const T_& t = 0) : ExecutePolicy_<T_>(t) { }
    };
    

    welche vorschläge habt ihr noch? ideen? anregungen?



  • Ich wäre für virtuelle Methoden. Die Basisklasse deklariert die notwendigsten Daten und der Anwender leitet eine eigene Klasse davon ab, die sich um's Zeichnen kümmert:

    class rectangle
    {
    public:
      virtual void show_rect() = 0;
      virtual void set_size(int width,int height) = 0;
      ...
    };
    
    //Anwender
    class DX_rectangle : public rectangle
    {
    public:
      virtual void show_rect()
      {/* zeichne Rechteck über DirectX*/}
      ...
    };
    


  • miller_m schrieb:

    ...der user meiner klasse unabhängig von seiner nutzung ein objekt verwenden kann...

    😕
    Sorry, das verstehe ich nicht.

    Vllt. deswegen verstehe ich auch die ganze Frage nicht....ich dachte immer, eine Klasse definiert, genau das ("Was kann ein User mit einem Objekt dieser Klasse machen ?") über die Funktionen und Attribute, die sie bereitstellt ...

    Gruß,

    Simon2.



  • Im Prinzip mußt du eine Schnittstelle definieren. Eine Möglichkeit wäre, das sie abstrakt ist und du verschiedene Implementierungen anbietest bzw. jemand anbieten kann. (siehe CStollst Antwort)

    Eine andere ist die Verwendung von Adaptern. D.h. eine Klasse definiert ebenfalls eine Schnittstelle, und enthält ein Member mit einer konkreten Klasse. Du kannst dann über den Adapter einfach die Aufrufe weiterleiten, an die Member-Klasse, die der Benutzer so nicht direkt benutzt.

    Und dann noch eine Möglichkeit: Context-Pattern. Finde ich immer noch am besten. 😃 Leider habe ich da im Netz keine gute Beschreibung gefunden. Das Context-Pattern wird aber in diversen Frameworks eingesetzt, z.B. im ACE. damit kannst du sogar deine Klasse komplett verstecken, also brauchst sie nicht mal in ein Header bekannt geben, weil der Benutzer nur die Context-Klasse zu Gesicht bekommt.



  • es handelt sich grösstenteils um templates somit müsste ich dann wieder irgendwelche "template/virtual hacks" machen (ist gerade kein anderer name eingefallen 😃 ) sprich weitere basisklassen und virtuals. ich dachte vielmehr an eine compiletimelösung.
    die methode ist auch mehr optional anzusehen 😉 einfacher ausgedrückt: das rechteck ist zum rechnen da, nicht zum zeichen.



  • Warum nicht sowas:

    class Rectangle {
    private:
        int x,y,...;
    public:
        template<class Drawer>
        void draw() {
            Drawer().draw(*this);
        }
    };
    
    struct ConsoleTextDrawer {
        void draw(const Rechteck& re) {
            std::cout << "x = " << re.getX() ...
        } 
    };
    
    //usage:
    Rectangle myrect;
    myrect.draw<ConsoleTextDrawer>();
    


  • Kurz und gut: schrieb:

    Warum nicht sowas:

    class Rectangle {
    private:
        int x,y,...;
    public:
        template<class Drawer>
        void draw() {
            Drawer().draw(*this);
        }
    };
    
    struct ConsoleTextDrawer {
        void draw(const Rechteck& re) {
            std::cout << "x = " << re.getX() ...
        } 
    };
    
    //usage:
    Rectangle myrect;
    myrect.draw<ConsoleTextDrawer>();
    

    ein haufen getter die die kapselung aufbrechen. gut im falle eines rechtecks wären es maximal vier, das ist aber imo nicht der sinn einer klasse.



  • Du erstellst ein Rechteck und willst nacher nicht mehr wissen wie gross es ist / wie seine Koordianten etc. sind?
    Zu was brauchst du denn diese ganzen Objekte? Ist es nur ein Beispiel mit dem Recheckt oder hast du wirklich geometrische Figuren?



  • class Rectangle
    {
    	// ...
    	template<class Functor>
    	void foo(Functor &func)
    	{
    		func(member1, member2, ...);
    	}
    };
    
    // user
    struct myFunc
    {
    	// haufen eigener funktionen
    	myFunc()
    	{
    		// eigene init aufrufen
    	}
    	~myFunc()
    	{
    		// eigene finisher aufrufen
    	}
    	void operator()(const Typ &t1, const Typ &t2, ...){ ... }
    };
    
    myFunc m;
    r.foo(m); // Rectangle
    


  • Kurz und gut: schrieb:

    Du erstellst ein Rechteck und willst nacher nicht mehr wissen wie gross es ist / wie seine Koordianten etc. sind?
    Zu was brauchst du denn diese ganzen Objekte? Ist es nur ein Beispiel mit dem Recheckt oder hast du wirklich geometrische Figuren?

    rechteck war natürlich nur ein beispiel 😃
    aber sollte ich die koordinaten wissen wollen?
    quick&dirty bsp:

    class rect
    {
        public:
            rect(int x_, int y_, int w_, int h_)
            : x(x_), y(y_), w(w_), h(h_) { }
    
            int seitenlänge() const { // ...
            int umfang() const { // ...
            int fläche() const { // ...
    
            rect& operator += (const rect& src) { // ...
    
            bool intersects( // ...
    
        private:
            int x, y, w, h;
    };
    

    ich sehe jetzt keinen grund warum ich getX() implementieren sollte



  • @thordk
    keine schlechte idee



  • Wenn niemand außen die internen Daten deines Objekts erfahren muß, muß das Objekt auch selber wissen, wie es dargestellt werden will. Also müsstest du den Zeichencode auch in der Rechteck-Klasse unterbringen (eventuell auf Basis einiger abstrakt vorgegebenen Grundoperationen):

    class drawer
    {
    public:
      virtual void draw_line(int x1,int y1,int x2,int y2) = 0;
      ...
    };
    
    class DX_drawer : public drawer
    {
    public:
      virtual void draw_line(...) {/*zeichne Linie mit DX*/}
      ...
    };
    
    //...
    
    class gobject
    {
    public:
      virtual void draw(drawer& target)=0;
    }
    
    class rectangle : public gobject
    {
      int y,x,w,h;
    public:
      ...
      virtual void draw(drawer& target)
      {
        target.draw_line(x,y,x+w,y);
        target.draw_line(x+w,y,x+w,y+h);
        target.draw_line(x+w,y+h,x,y+h);
        target.draw_line(x,y+h,x,y);
      }
    };
    
    ...
    DX_drawer the_drawer;
    
    rectangle r;
    r.draw(the_drawer);
    


  • CStoll schrieb:

    Wenn niemand außen die internen Daten deines Objekts erfahren muß, muß das Objekt auch selber wissen, wie es dargestellt werden will.

    jein, was wäre wenn der user linksrum statt rechtsrum zeichnen möchte oder sein rechteck aus zwei dreiecken erstellen will usw usw
    ich hoffe ich fange jetzt nicht an zu nerven 😃 ich suche ja nur nach ideen und lösungsansätzen. vermutlich werde ich aber in die policy geschichte gehen.
    dank euch allen


Anmelden zum Antworten