Schrift
[thread]8353[/thread]

Perl OOP (Seite 2)



<< |< 1 2 >| >> 13 Einträge, 2 Seiten
sid burn
 2006-09-22 18:43
#70149 #70149
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
schon klar, aber warum?

Ich denke da in erster Linie an die erweiterbarkeit. Es werden wohl noch ein paar methoden hinzu kommen. Ich persönlich denke einfach so. Bevor ich Methoden habe die:

duration_add
duration_sub
duration_set
...

besitze, dann sollte duration doch eher ein eigener Namespace sein. Wenn man ständig vor etwas einen Prefix schreibt, ist das für mich doch eher ein Indiz ein Namespace zu benutzen, und die Funktionen unter diesem Namespace zur Verfügung zu stellen.

Quote
ich weiß nicht, bei simplen integern oder strings rufst du doch in anderen sprachen auch keine methode mehr auf.

In anderen Sprachen sind meist Integer und Strings schon Objekte. Z.B. bei Ruby und Python.

Bei Ruby kannst du z.B. einfach bei allem ein ".class" anhängen und du bekommst den Objekttyp zurück. Möchtest du den Inhalt der variable klein haben hängst du einfach ein ".lc" dran. "$string.lc" und der Text ist kleingeschrieben.

Ich halte zwar von solcher einer Programmierung nicht all zu viel manchmal ist es aber auch nützlich. Und bei Perl6 wird sowas ja auch kommen. Man schaue sich "@array.elem" an um die Anzahl der Elemente zu bekommen.

Ich weiß nciht ob es kommt, aber man könnte sich sicherlich auch solche Sachen vorstellen. "@array.add('Hallo')" Um z.B. ein Element im Array hinzuzufügen. Trotzdem sollte "@array" immer noch einfach nur ein Array Repräsetieren. Die Methoden dafür sind halt Optional.

Quote
moment, moment. du hast mich glaube ich nicht verstanden. net_ftp_connect ist ja witzlos. wie gesagt, simple integer oder strings finde ich als objekte overkill. und da, wo du meinst, ein objekt haben zu müssen, mach auch eins. aber nicht implizit bei *jedem* attribut.

Ich wollte es auch gar nicht implizit bei jedem Attribut machen, und nur da wo es benötigt wird. den Code oben ist erstmal nur ein Test Code um die Technik dahinter zu verstehen und zu schauen wie man soetwas erstmal nur Implementiert.

Zum anderen werde ich nachher kein String oder so abspeichern. "$user->duration" soll mir direkt die Dauer aus der Datenbank auslesen. Und wenn ich es als Setter benutze soll der Eintrag in der Datenbank auch direkt verändert werden. Möchte ich den Eintrag in der Datenbank halt erhöhen kann ich einfach ein "add" hinten anhängen. Mir kommt das jedenfalls natürlicher vor.

Allerdings muss ich selber auch gleichzeitig dagegen sprechen. Wenn ich 4 Attribute als Klasse Implementiere, und dann 2 wiederrum als normalen Skalar kann dies ziemlich verwirrend sein, was den nun Klasse oder Skalar war.

Quote
jetzt bin ich ganz verwirrt. wenn der user eine methode add_duration hat, warum steht die plötzlich "für "name", "password", "email" zur Verfügung"?

Gute Frage!
Keine Ahnung, wo ich das geschrieben habe, war ich wohl etwas Verwirrt gewesen.

Quote
und wenn ich die duration eines users erhöhen will (was auch immer das bedeutet), dann gehört diese methode für mich schon zum user.

Ja es gehört zum User, aber eine Ebene Tiefer. Ich möchte ja nicht mit dem kompletten User Arbeiten, sondern nur mit dem speziellen Attribut.

Deswegen würde man ja auch "$user->duration_add" schreiben. Um klarzustellen das sich das "add" auf duration bezieht. Wenn man "$user->add" schreibt, würde man nicht Wissen was hier genau passiert. Daher finde ich "$user->duration->add" ziemlich natürlich.

Wenn ich vor etwas einen Prefix schreibe ist das für mich halt eher ein Indiz das ich vielleicht einen neuen namespace oder eben eine Klasse daraus machen sollte. So denke ich jedenfalls.

Quote
bis jetzt sehe ich nur, dass dir ->foo_bar nicht gefällt und du lieber ->foo->bar schreiben willst. das finde ich gut für attribute, die richtige objekte sind. wenn du der meinung bist, duration verdient eine eigene klasse, dann hält dich nichts davon ab, das zu machen.

Ich bin ja selber auch nicht damit zu frieden. Für mich sieht es auch nach Overkill aus.

Ich hätte ja gedacht das es vielleicht noch andere Tricks gibt sowas zu machen, was dann auch etwas Effizenter wäre. Ich habe mir auch überlegt ob man nicht in der Funktion angibt was man haben möchte. "Also z.B. $user->password( 'plain' )" was mir dann das Plain Passwor liefert anstatt das "Verschlüsselte". Allerdings scheint mir der Weg auch etwas komisch und nicht so Intuitiv. Bei der Möglichkeit müsste ich natürlich wieder getter und setter voneinander Trennen. Ich mag aber ehrlich gesagt beides in einem zu haben.

Quote
u.a. den vorteil, dass man auch leicht readonly-klassen erzeugen kann und man den unterschied sehr schnell sieht. naja, PBP hat mich da überzeugt =)

Soweit habe ich noch nicht gelesen. ;) Aber auch im Alpaka Buch wurde gesagt das das Trennen davon besser wäre. Habe allerdings die gründe vergessen. ;)


Wie ich das jetzt letztendlich Umsetze weiß ich noch nicht. Für mich wirkt das Teilweise auch alles zu kompliziert, was ich ehrlich gesagt auch etwas schade finde.


Kann man nicht den "->" überladen so das er zwei Argumente einer Subroutine übergibt? ;) So dass "$user->set_duration->add" letztendlich einem "user::set_duration( 'anne', 'add') entspricht? ;)

Dann könnte ich die Schreibweise beibehalten, und habe keine verschachtelte Klassen.\n\n

<!--EDIT|sid burn|1158936503-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
pq
 2006-09-22 19:25
#70150 #70150
User since
2003-08-04
12209 Artikel
Admin1
[Homepage]
user image
[quote=sid burn,22.09.2006, 16:43]Zum anderen werde ich nachher kein String oder so abspeichern. "$user->duration" soll mir direkt die Dauer aus der Datenbank auslesen. Und wenn ich es als Setter benutze soll der Eintrag in der Datenbank auch direkt verändert werden.[/quote]
oha. sorry, dass ich schon wieder was einzuwenden habe.
bei einem normalen getter ein select auf die datenbank zu machen kann
je nach anwendung *sehr* ineffizient sein.
gerade gestern erlebt. eine klasse bei uns hat eine methode, die eine
reihe von strings zurückliefert. diese sind keine direkten attribute.
beim aufruf dieser methode wird ein select auf die datenbank gemacht.
bis vor kurzen lieferte die methode aber ein direktes attribut.
nun gibt es eine anwendung, die einen export macht und sich,
sagen wir, 100.000 objekte aus der db holt. für jedes objekt holt sich
der export nun noch über die genannte methode die strings.
das sind 100.000 selects extra. der export läuft jetzt doppelt so lange
wie vorher. nicht gut.

dasselbe gilt für store.
ich würde lieber eine methode store implementieren und nicht implizit beim aufruf des setters auf die datenbank gehen. kann dann
auch störend sein, wenn du das mal nicht haben willst.

vielleicht solltest du CPAN:DBIx::Class o.ä. verwenden, da
kann man dann auch angeben, welche attribute immer gleich mit
dem ersten select geholt werden sollen und welche nicht.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
sid burn
 2006-09-22 22:20
#70151 #70151
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
oha. sorry, dass ich schon wieder was einzuwenden habe.

Wieso Sorry?
Ich hab doch extra den Thread erstellt damit ich ein paar einwände bekomme. Wenn ich keine Einwände akzeptieren würde, wäre ich ja ein schlechter Programmierer. ;)

Quote
bei einem normalen getter ein select auf die datenbank zu machen kann je nach anwendung *sehr* ineffizient sein.gerade gestern erlebt. eine klasse bei uns hat eine methode, die eine
reihe von strings zurückliefert. diese sind keine direkten attribute.
beim aufruf dieser methode wird ein select auf die datenbank gemacht.
bis vor kurzen lieferte die methode aber ein direktes attribut.
nun gibt es eine anwendung, die einen export macht und sich,
sagen wir, 100.000 objekte aus der db holt. für jedes objekt holt sich
der export nun noch über die genannte methode die strings.
das sind 100.000 selects extra. der export läuft jetzt doppelt so lange
wie vorher. nicht gut.

Ja das habe ich mir auch schon gedacht. Vielleicht sollte ich etwas mehr zum Thema erzählen warum ich das Trotzdem machen möchte. Ich habe für die Arbeit ein kleines Webinterface geschrieben um einen FTP Server zu verwalten. Zu der Benutzerverwaltung kommen halt noch Sachen dazu wie eMail Benachrichtigung wenn ein Account angelegt wurde, automatisches Löschen von Benutzern wenn Ihre Gültigkeitsdauer abgelaufen ist etc.

Das ganze läuft soweit schon, allerdings habe ich auch bei solch einen kleinen Projekt ziemlich viel Erfahrung dazu gewonnen. Programmiere halt noch nicht so lange. ;)

Ich habe das ganze mehr so geschrieben wie du es bisher beschrieben hast. Sprich ich stelle einfach durch einen Befehl z.B. eine Datenbankverbindung her. Und wenn ich Benutzer auslese werden alle Ihre Daten mit einem einzigen SELECT Befehl ausgelesen. Ich erzeuge halt ein User Objekt und packe alle Daten in dieses Objekt.

Bei der Logik sind mir aber ein paar probleme untergekommen. Zum einen hatt das User Objekt eine Fehlerüberprüfung. Das heißt es akzeptiert keine UID kleiner 1000 etc. Diese Überprüfung habe ich direkt in das User Objekt eingebaut.

Das Problem war wenn ich die Daten letztendlich Auslese und die HTML Seite aufgebaut habe. Den dann habe ich die Daten ausgelesen und über die Setter Methoden das Objekt gefüllt. Tjo und genau da war das Problem. Wenn in der Datenbank eine 500 steht. (Vielleicht war ja früher mal 500 als UID erlaubt) und ich damit mein User Objekt erzeuge dann habe ich alle Werte kleiner 1000 verworfen und einfach den Konfigurierten default_uid Wert genommen, wenn die min_uid nicht erfüllt war.

Letztendlich hat also die Webseite bei der Anzeige völlig andere Werte angezeigt als sie in der Datenbank standen. Das Problem habe ich nachher umgangen so das ich beim Auslesen die Werte direkt fülle, und nicht über Setter Methoden. Das muss ich sowieso machen. Sonst würde mir die Setter Methode für das password den Hash nochmal Hashen und erst dann anzeigen.

Eine andere Sache war die gewesen das wenn ich z.B. einfach nur ein Passwort ändern möchte, ich unnötig viel Code schreiben muss. z.B. hole ich mit "my $user = $ftp->getuser('anne')" die Benutzerinformationen zum User "anne", und das gibt mir ein Benutzerobjekt zurück. Wenn ich nur das Passwort des aktuellen Benutzers Löschen möchte, dann muss ich letztendlich wiederrum ein neues Objekt erstellen, dann die alten Werte in das neue Kopieren. Und hierbei darf ich keine Setter Methode Benutzen. Den wenn ich wie gesagt das passwort wieder mit einer Setter Methode schreibe, wird der Hash nochmals gehasht. Womit ein einloggen mit diesem benutzer nicht mehr Möglich wäre.

Und nachdem ich beide Objekt hatte, habe ich eine Methode Modify aufgerufen. "$ftp->modify( $old_user, $new_user)" das letztendlich den alten benutzer genommen hat, und dann die veränderten Werte in die Datenbank schreibt.

Ziemlich viel Aufwand. Zwar läuft das Webinterface aber ich möchte sicherlich noch etwas weiter Lernen. Daher habe ich mir überlegt ob es nicht deutlich Sinvoller ist die Daten einfach direkt auszulesen. Dann habe ich jedenfalls das Problem mit dem Auslesen der Daten und den Settern nicht mehr. Weil meine Klasse ja direkt mit der Datenbank Kommuniziert.

Und beim Setter das gleiche, die Werte werden sofort geschrieben. Natürlich kommt trotzdem vorher eine Fehlerüberprüfung. Jedenfalls um das Passwort dann neu zu setzen bräuchte ich nicht alle anderen Werte auslesen. Es würde praktisch folgender Code reichen.
Code: (dl )
1
2
3
my $user = $ftp->getuser('anne');
$user->password( "foobar" );
$ftp->disconnect;

Solch ein Interface finde ich dann doch deutlich angenehmer.

Und passend mit der Möglichkeit das hinter den einzelnen Werten Klassen stehen, würde ich dann auch folgendes machen.

Code: (dl )
$user->password->random;

Was dann einfach ein neues Random Passwort erzeugt, und dann natürlich auch gleichzeitig das "Plaintext" Passwort setzt, das ich noch für die Mail Versundung benötige.

Jedenfalls finde ich das Handlicher und einfacher. Problem ist aber halt die Performance. Ich greife nicht mehr mit einem Select auf mehrere Attribute drauf zu, sondern immer jedes Attribut einzelnd. Die Performance ist in diesem Fall aber vernachlässigbar.

Interesse wie ich das Beschleunigen könnte würden mich aber trotzdem Interessieren. Das Interface so wie ich es jetzt gerade beschrieben habe würde ich aber gerne beibehalten, das finde ich jedenfalls Handlicher. Auser du weißt eine Bessere Möglichkeit wie ich das ganze machen könnte.

Quote
vielleicht solltest du CPAN: DBIx::Class o.ä. verwenden, da
kann man dann auch angeben, welche attribute immer gleich mit
dem ersten select geholt werden sollen und welche nicht.

Werde ich mir mal anschauen.\n\n

<!--EDIT|sid burn|1158949514-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
<< |< 1 2 >| >> 13 Einträge, 2 Seiten



View all threads created 2006-09-21 19:24.