Om jag har en databas klass som sköter insert, update, delete, connect etc. Sedan har jag en annan klass som hanterar medlemmar, där jag kan add, delete, update etc.
I klassen "medlemmar" så måste jag ju kommunicera med databasen ganska mycket. Ska jag göra att medlemmar "extendar" databas klassen? Blir ju lite bakvänt, men hur använder jag databas-klassen i medlemmar klassen på bästa sätt?
Det kan ju t.ex se ut så här:
$member->add("Urme", "stad", "e-mail");
Då görs det ju massa kontroller på användarnamnet, stan och e-posten innan det ska läggas in i databasen (mysql).
Hur ska jag göra detta på bästa sätt? Helst av allt skulle jag ju inte vilja ansluta till databasen i varje funktion i medlemsklassen heller.
Ska jag göra att medlemmar "extendar" databas klassen?
Nej! En tydlig indikiation på att arv är olämpligt, är när "y är en x" inte får en logisk innebörd, dvs medlem är en databas låter ju sådär eller hur?
Din medlems-klass bör inte känna till något om databas/databas-operationer överhuvudtaget! Mitt förslag är att du läser på om design-mönstret DAO (Data Access Object) för att få förslag på hur du kan implementera det hela. Bra info och exempel finns här: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
Nej! En tydlig indikiation på att arv är olämpligt, är när "y är en x" inte får en logisk innebörd, dvs medlem är en databas låter ju sådär eller hur?
Jo var det jag tänkte :) blir inte logiskt alls.
Din medlems-klass bör inte känna till något om databas/databas-operationer överhuvudtaget! Mitt förslag är att du läser på om design-mönstret DAO (Data Access Object) för att få förslag på hur du kan implementera det hela. Bra info och exempel finns här: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
Man kommer ihåg varför man inte har satt sig in i OOP på riktigt när man kollar på en sådan där sida :) Ska ta och läsa igenom den iaf och se om det klarnar lite bättre.
Har läst igenom den där sidan nu men har inte allt på banan..
Är det helt tokigt att göra så här:
Vi säger att vi har en databasklass (mysql) i en fil som heter class.mysql.php
Sedan har vi en annan klass som ska spara något i en databas, är det fel att göra så här i konstruktorn då?
function _construct() {
require_once("class.mysql.php");
$this->mysql = new Mysql( "localhost", "user", "pass", "db" );
}
Och sedan i en funktion i klassen;
function adduser($username, $city) {
$this->mysql->query( "INSERT INTO .....'");
}
Hade det inte varit smartare att instantiera db-klassen utanför och skicka med den som en variabel i konstruktorn?
typ:
$db=new Mysql( "localhost", "user", "pass", "db" );
$member=new Member($db)
class Member {
private $db;
public function __contruct($db) {
$this->db=$db;
}
public function adduser($username, $city) {
$this->db->query( "INSERT INTO .....'");
}
}
På så sätt så kan du återanvända databas-objektet till andra grejer och slipper instantiera det för varje klass.
Jag antar att du använder MySQL? Dina DAO-klasser blir då ganska MySQL-specifika. Jag skulle göra mina DAOs till singleton och låta dessa ärva från en basklass som sköter databaskommunikationen.
Dvs: MySqlDAO är super klassen som andra DAO:s ärver av... Du skulle även kunna låta din MySqlDAO ärva från en BaseDAO, dvs en klass som innehåller funktionalitet som inte är DBMS-specifikt.
Ett litet exempel på hur du skulla kunna göra.
abstract class MySqlDAO {
private $db;
public function __contruct() {
$this->db = new Mysql( "localhost", "user", "pass", "db" );
}
// Annan gemensam funktionalitet...
}
interface IMemberDAO
{
public function addMember($username, $city);
// Mer metod-deklarationer för MemberDAO här...
}
class MySqlMemberDAO extends MySqlDAO implements IMemberDAO {
private static $instance;
private function __contruct() {
parent::__construct();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new MySqlMemberDAO();
}
return self::$instance;
}
public function addMember(Member $member) {
$sql = "INSERT INTO member (username, city)
VALUES('$member->getUsername()','$member->getCity()')";
$this->db->query($sql);
}
}
class Member {
private $username;
private $city;
public function __construct($username, $city) {
$this->username = $username;
$this->city = $city;
}
public function getUsername() {
return $this->username;
}
public function setUsername($username) {
$this->username = $username;
}
public function getCity() {
return $this->city;
}
public function setCity($city) {
$this->city = $city;
}
}
// Altogether now...
$member = new Member("Janne", "Göteborg");
MySqlMemberDAO::getInstance()->addMember($member);
// Eller så skriver du det så här, kanske mer läsbart..
$member = new Member("Janne", "Göteborg");
$memberDAO = MySqlMemberDAO::getInstance();
$memberDAO->addMember($member);
Helt otestat, men hoppas du förstår principen. En förbättring skulle kunna vara att använda PDO eller mysqli för att få tillgång till prepared statements när du skapar dina sql-frågor :)
Nu vet jag att du sade att de var otestat, men jag skulle vilja återkomma med lite synpunkter. :)
Du har ett fel i Member på __construct().
Dessutom om vi ska vara så strikta, borde det väl vara en idé att type hinta i MySqlMemberDAO->addMember?
Typ:
public function addMember(Member $member) {
$sql = "INSERT INTO member (username, city)
VALUES('$member->getUsername()','$member->getCity()')";
$this->db->query($sql);
}
Har kollat lite mera på det nu, och varför jag inte kört PDO tidigare vet jag inte, antagligen för att jag inte har kodat speciellt mycket PHP på senare tid och när det väl har gjorts har det gjorts av gammal vana :)
Jag körde på coliones exempel fast med PDO
$db = new PDO('mysql:host=localhost;dbname=test', 'test','test');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
class Users {
private $db;
public function __construct($db) {
$this->db=$db;
}
public function listusers($firstname, $lastname) {
$stmt = $this->db->prepare('SELECT firstname, lastname, email FROM pdo_test WHERE firstname = ? AND lastname = ?');
$stmt->execute(array($firstname, $lastname));
$result = $stmt->fetchAll();
return $result;
}
public function adduser($firstname, $lastname, $email) {
$stmt = $this->db->prepare('INSERT INTO pdo_test (firstname, lastname, email) VALUES(?, ?, ?)');
$stmt->execute(array($firstname, $lastname, $email));
}
}
$users = new Users($db);
$users->adduser("Kalle", "Karlsson", "kalle@kalle.se");
$result = $users->listusers('Kalle', 'Karlsson');
Är detta acceptabelt eller är det lika bra att försöka ge sig in på "DAO" konceptet, förstår i princip det mesta, men när jag testade det så fick jag ett något felmeddelande på prepare() funktionen i PDO, förmodligen kanske jag inte fattade exakt hur jag skulle gå tillväga ändå :) Antar att det bara gäller att läsa väldigt mycket och prova sig fram.
UrMe: Det där ser bra ut, vid enklare domän modeller så är det en helt duglig lösning.
Campusa: Om jag inte ser helt fel, så senaste versionen av din kod instanserar en databaskoppling per utökad klass? Känns inte direkt optimalt, sen så är ju singletons inget att rekommendera heller.
Campusa: Om jag inte ser helt fel, så senaste versionen av din kod instanserar en databaskoppling per utökad klass?
Japp det har du rätt i och det är jag fullt medveten om. Detta var ett snabbt utkast som jag skrev ihop igår kväll och naturligtvis finns det utrymme för förbättringar.
thr skrev:
sen så är ju singletons inget att rekommendera heller.
Du får gärna motivera... I normala fall brukar jag factories för att skapa mina DAOs (som inte är singleton).
287 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e