Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Zugriff auf bestimmte Klassen beschränken

6 views
Skip to first unread message

Thomas Preymesser

unread,
Jun 3, 2011, 5:17:40 AM6/3/11
to
Hi!

Ich möchte gerne folgendes Feature in Ruby realisieren: Ich habe eine Klasse A

class A

def initialize
# do something
end
end

und eine oder mehrere Klassen, die von A abgeleitet sind (hier X und Y)

require 'a'

class X < A
def initialize
super
# do something more for x
end
end

require 'a'

class Y < A
def initialize
super
# do something more for y
end
end

jetzt würde ich gerne den Zugriff auf Methoden (z.B. initialize) so beschränken können, daß der Aufruf nur von festgelegten Klassen möglich ist. Ich möchte bei Klasse A beispielsweise in etwa so etwas schreiben können:

visible_to :initialize, [:X, :Y]

soll heißen, wenn initialize (oder beliebige andere Methoden) nicht aus der Liste der angegebenen Klassen heraus aufgerufen wird, soll ein Fehler ausgelöst werden, wie bei den folgenden Tests angedeutet:


require 'a'
require 'x'
require 'y'
require 'test/unit'

class TestEv < Test::Unit::TestCase
def test_ok
assert_nothing_raised(VisibilityError) {
x = X.new
y = Y.new
}
end
def test_error
assert_raise(VisibilityError) {
a = A.new
}
end
end


Wie könnte man so etwas realisieren?

Gruß,
-Thomas

Robert Klemme

unread,
Jun 3, 2011, 7:52:55 AM6/3/11
to

Zunächst mal ist das etwas verdächtig, wenn Du in die Oberklasse eine
Abhängigkeit zu Unterklassen einbaust. Normalerweise sollte die
Abhängigkeit immer in der anderen Richtung laufen.

> require 'a'
> require 'x'
> require 'y'
> require 'test/unit'
>
> class TestEv< Test::Unit::TestCase
> def test_ok
> assert_nothing_raised(VisibilityError) {
> x = X.new
> y = Y.new
> }
> end
> def test_error
> assert_raise(VisibilityError) {
> a = A.new
> }
> end
> end
>
>
> Wie könnte man so etwas realisieren?

Du weißt während der Konstruktion, zu welcher Klasse Deine Instanz gehört:

irb(main):001:0> class A
irb(main):002:1> def initialize; p self.class; end
irb(main):003:1> end
=> nil
irb(main):004:0> class X < A; end
=> nil
irb(main):005:0> A.new
A
=> #<A:0x1075a5fc>
irb(main):006:0> X.new
X
=> #<X:0x1075a6b0>

Das Wissen kannst Du für eine Prüfung ausnutzen. Das gleiche gilt
natürlich für andere Methoden. Du könntest ein bisschen
metaprogrammieren und eine Instanzmethode in Klasse Module einbauen, die
erst die Prüfung macht und dann die originale Methode aufruft.
Sonderlich sicher ist das allerdings nicht, denn jeder kann die Methode
überschreiben und dann ist Deine Sicherheit perdu.

Wofür brauchst Du das denn?

Ciao

robert


--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Johannes Held

unread,
Jun 6, 2011, 11:51:27 AM6/6/11
to
On 03.06.2011 13:52, Robert Klemme wrote:
> Wofür brauchst Du das denn?
Sieht mir ein wenig nach dem FactoryPattern aus.

--
Johannes

Thomas Preymesser

unread,
Jun 10, 2011, 8:06:36 AM6/10/11
to
Am Freitag, 3. Juni 2011 13:52:55 UTC+2 schrieb Robert Klemme:

> Zunächst mal ist das etwas verdächtig, wenn Du in die Oberklasse eine
> Abhängigkeit zu Unterklassen einbaust. Normalerweise sollte die
> Abhängigkeit immer in der anderen Richtung laufen.

Ich sehe das eigentlich nicht als Abhängigkeit. Die Oberklasse stellt einige Methoden zur Verfügung, die die Unterklassen gemeinsam verwenden. Der externe Benutzer könnte theoretisch ein Objekt der Oberklasse erzeugen (und kann er in der jetzigen Form auch praktisch), aber das würde ihm überhaupt nichts nutzen, da wesentliche Funktionalität erst in den Unterklassen implementiert ist. Deswegen soll in der Oberklasse der Zugriff nur auf die Unterklassen beschränkt sein.



> irb(main):006:0> X.new
> X
> => #<X:0x1075a6b0>

ah OK, das ist ja doch einfacher als ich dachte. Dann muß ich das ganze nur noch in eine schicke Methode verpacken.

> Sonderlich sicher ist das allerdings nicht, denn jeder kann die Methode
> überschreiben und dann ist Deine Sicherheit perdu.

Das macht nichts. Es soll eher gegen unbeabsichtigtes Initiieren der Oberklasse helfen. Wenn jemand unbedingt will, dann kann er natürlich alles überschreiben, aber so jemand weiß dann auch (hoffentlich), was er tut.


> Wofür brauchst Du das denn?

In einem Gem von mir (Roo) habe ich eine Klasse, die allgemeine Methoden implementiert, die mit Spreadsheets zu tun haben (beispielsweise cell() um den Inhalt einer Zelle zurückzugeben, oder to_xml() oder to_csv()). Darauf aufbauend gibt es jeweils Klassen, die Excel-Spreasheets oder Openoffice-Spreadsheets implementieren, also z.B. auch das Einlesen der Datei aus einer Datei in eine interne Struktur. Der Benutzer soll also nicht (versehentlich) die allgemeine Klasse verwenden können, weil diese alleine höchst unvollständig wäre) sondern diese soll nur den Klassen für eine spezielle Spreadsheet-Art zur Verfügung stehen.

-Thomas

Robert Klemme

unread,
Jun 10, 2011, 12:14:42 PM6/10/11
to
On 10.06.2011 14:06, Thomas Preymesser wrote:
> Am Freitag, 3. Juni 2011 13:52:55 UTC+2 schrieb Robert Klemme:
>
>> Zunächst mal ist das etwas verdächtig, wenn Du in die Oberklasse
>> eine Abhängigkeit zu Unterklassen einbaust. Normalerweise sollte
>> die Abhängigkeit immer in der anderen Richtung laufen.
>
> Ich sehe das eigentlich nicht als Abhängigkeit. Die Oberklasse stellt
> einige Methoden zur Verfügung, die die Unterklassen gemeinsam
> verwenden. Der externe Benutzer könnte theoretisch ein Objekt der
> Oberklasse erzeugen (und kann er in der jetzigen Form auch
> praktisch), aber das würde ihm überhaupt nichts nutzen, da
> wesentliche Funktionalität erst in den Unterklassen implementiert
> ist. Deswegen soll in der Oberklasse der Zugriff nur auf die
> Unterklassen beschränkt sein.

Ob Du das so siehst oder nicht: es ist eine Abhängigkeit, denn die
Oberklasse muss die Unterklassen kennen.

>> irb(main):006:0> X.new X => #<X:0x1075a6b0>
>
> ah OK, das ist ja doch einfacher als ich dachte. Dann muß ich das
> ganze nur noch in eine schicke Methode verpacken.

Mit Schleifchen bitte!

>> Wofür brauchst Du das denn?
>
> In einem Gem von mir (Roo) habe ich eine Klasse, die allgemeine
> Methoden implementiert, die mit Spreadsheets zu tun haben
> (beispielsweise cell() um den Inhalt einer Zelle zurückzugeben, oder
> to_xml() oder to_csv()). Darauf aufbauend gibt es jeweils Klassen,
> die Excel-Spreasheets oder Openoffice-Spreadsheets implementieren,
> also z.B. auch das Einlesen der Datei aus einer Datei in eine interne
> Struktur. Der Benutzer soll also nicht (versehentlich) die allgemeine
> Klasse verwenden können, weil diese alleine höchst unvollständig
> wäre) sondern diese soll nur den Klassen für eine spezielle
> Spreadsheet-Art zur Verfügung stehen.

Das kann man aber auch anders entwerfen: es gibt eine
Spreadsheet-Klasse, die die wichtige Funktionalität enthält. Und dann
gibt es für jedes Lese- und Schreibformat eine Klasse, die die
Konvertierung macht. Dafür brauchst Du dann auch keine Vererbung. Die
kommt höchstens ins Spiel, wenn es Varianten von Formaten gibt, die sich
nur geringfügig unterscheiden (dann zwischen den Konvertern), oder wenn
Du Spreadsheet-Varianten mit unterschiedlicher Funktionalität hast.

0 new messages