Avatar billede j-e Nybegynder
19. februar 2010 - 20:11 Der er 21 kommentarer og
1 løsning

Hvad kan abstract, interface,final og hvad skal jeg bruge det til i oop?

Jeg er ny med hensyn til oop. Jeg forstår godt den grundlæggene. Men jeg vil gerne vide med nogle af de andre ting i det.. Har søgt og læst en helt masse men forstår ikke rigtigt abstract, interface,final og formålet med dem?
Avatar billede repox Seniormester
19. februar 2010 - 20:46 #1
Har du prøvet at læse manualen?

Du siger du 'forstår det grundlæggende', men det at kunne lave interfaces samt abstrakte klasser er grundlæggende.

Interfaces fortæller PHP hvad en klasse skal indeholde af funktioner, uden at angive hvad funktionerne gør.
http://dk2.php.net/manual/en/language.oop5.interfaces.php

Abstrakte klasser kan ikke instansieres, men du kan tilføje funktionalitet som kan nedarves af andre klasser. Alle abstrakte funktioner i en abstrakt klasse skal defineres af det nedarvende objekt.
http://dk2.php.net/manual/en/language.oop5.abstract.php

Final bruges til at afslutte noget. Det vil sige at hvis du har en klasse der er defineret 'final' kan denne ikke nedarves.
Har du en funktion i din klasse der er defineret final, kan denne ikke overskrives af en nedarvende funktion.
http://dk2.php.net/manual/en/language.oop5.final.php
Avatar billede j-e Nybegynder
19. februar 2010 - 21:50 #2
#1 Ja, jeg har læst rigtigt meget i manualen. Kan dog bare ikke forstå hvad det skal bruges til.

Jeg beklager at jeg omtalte min viden som grundlæggende så.

Jeg forstår godt hvad interfaces kan. Men hvad kan jeg bruge det til og hvad får jeg ud af det?

Så man skal lave en klasse abstrakte hvis formålet med den er at nedarve den til andre klasser? Hvad mener du med alle abstrakte funktioner i en abstrakt klasse skal defineres af det nedarvende objekt?

Er med final nu.
Avatar billede repox Seniormester
19. februar 2010 - 22:37 #3
Interfaces er godt hvis du er igang med et projekt hvor der er flere udviklere tilknyttet (ligeledes abstrakte klasser, men det bør give sig selv herefter).

For at noget kan blive rigtigt OOP, og ikke bare filer med klasser i, bør du anvende de muligheder der er for nedarvning og polymorfi.

Eksempelvis kunne man forestille sig at du skulle lave en slags bilportal.
Til den bilportal vil du anvende nogle klasser (objekter) til at præsentere bildata. Men da du ikke er den eneste udvikler på bilportalen, er det vigtigt at I bliver enige om hvad et objekt skal indeholde for at outputtet kan blive ensartet.

Her kan man lave et interface:


  interface Biler
  {
    public function getYear( $model );
    public function getPrice( $model );
    public function getModels();
    public function getImages( $model );
    public function getAdditionalInfo( $model );
  }



Super, nu ved jeg som udvikler at jeg skal implementere ovenstående interface og hvis jeg ikke har de funktioner med som er beskrevet ovenfor, vil mit objekt ikke virke.

Jeg kan således lave forskellige objekter og være sikker på at ovenstående funktioner vil være en del af mit objekt - og det gælder alle udviklere.

Eksempelvis vil udvikler nummer 1 måske gøre således:


  class Seat_Ibiza implements Biler
  {

    public function getYear( $model )
    {
      $db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
      return $db->result->year;
    }

    public function getPrice( $model );
    {
      $db->queryItem("SELECT price FROM tCars WHERE model = '$model'");
      return $db->result->year;
    };


    public function getModels()
    {
      $sql = "SELECT model FROM tCarModels WHERE carType = 'SEAT' ORDER BY model ASC";
      $db->query($sql);
      return $db->result->result2array();
    };

    public function getImages( $model )
    {
      $sql = "SELECT filename, filecaption FROM tCarImages WHERE modelType = '$model' ORDER BY filename ASC";
      $db->query($sql);
      return $db->result->result2array();
    };
   
    public function getAdditionalInfo( $model )
    {
      $db->queryItem("SELECT additionalInfo FROM tCars WHERE model = '$model'");
      return $db->result->additionalInfo;
    };


  }



mens udvikler nummer 2 mener at nedenstående er smartere:



  class Peugeot_406 implements Biler
  {
      private $models = array();
      private $years = array();
      private $prices = array();
      private $images = array();
      private $info = array();
 
    public function __construct()
    {
      $this->_populateModels();
      $this->_populateYears();
      $this->_populatePrices();
      $this->_populateImages();
      $this->_populateInfo();
    }

    public function getYear( $model )
    {
        return $this->years[$model];
    };

    public function getPrice( $model );
    {
      return $this->prices[$model];
    };


    public function getModels()
    {
      return $this->models;
    };

    public function getImages( $model )
    {
      return $this->images[$model];
    };
   
    public function getAdditionalInfo( $model )
    {
      return $this->info[$model];
    };


    private function _populateModels()
    {
      $sql = "SELECT model FROM tCarModels WHERE carType = 'SEAT' ORDER BY model ASC";
      $db->query($sql);
      $this->models = $db->result->result2array();
    };

    private function _populateYears()
    {
      foreach($this->models as $model)
      {
        $db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
        $this->years[$model] = $db->result->year; 
      }
    };

    private function _populatePrices()
    {
      foreach($this->models as $model)
      {
        $db->queryItem("SELECT price FROM tCars WHERE model = '$model'");
        $this->prices[$model] = $db->result->price; 
      }
    };

    private function _populateImages()
    {
      foreach($this->models as $model)
      {
        $sql = "SELECT filename, filecaption FROM tCarImages WHERE modelType = '$model' ORDER BY filename ASC";
        $db->query($sql);
        $this->images[$model] = return $db->result->result2array();
      }
   
    };
   
    private function_populateInfo()
    {
      foreach($this->models as $model)
      {
        $db->queryItem("SELECT additionalInfo FROM tCars WHERE model = '$model'");
        $this->info[$model] = $db->result->additionalInfo; 
      }     
    };


  }



Nu ved jeg så at uanset hvilken type bil jeg skal hente info om vil alle oplysningerne altid være tilgængelige på den samme måde, uanset måden klassen er lavet på:




  $bil = $_POST["bil"];
 
  if( !class_exists($bil) )
  {
  header("Location: notfound.php");
  exit;
  }
 
  $bilObj = new $bil();

  $modeller = $bilObj->getModels();
  ...





På den måde har du både brugt interfaces og polymorfi.

En abstrakt klasse kan bruges på nogenlunde samme måde.
Men vi tager udgangspunkt i det førnævnte; vi har bare behov for at at tilføje standard funktionalitet til vores bil objekter:


  abstract class Biler
  {
      protected $db; // vores database abstraktionslag kan tilgås gennem denne
 
      protected function __construct()
      {
          $this->_startMysqlConnection();
      }
     
      private function _startMysqlConnection()
      {
          $this->db = new MysqlObj("localhost", "brugernavn", "kodeord", "database");
      }
 
    abstract public function getYear( $model );
    abstract public function getPrice( $model );
    abstract public function getModels();
    abstract public function getImages( $model );
    abstract public function getAdditionalInfo( $model );
  }



Og istedet for at implementere interfacet fra før, extender vi nu blot vores klasser:

Udvikler nr 1


  class Seat_Ibiza implements Biler
  {

    public function getYear( $model )
    {
      $db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
      return $db->result->year;
    }

        ...




Udvikler nr 2:


  class Peugeot_406 extends Biler
  {
      private $models = array();
      private $years = array();
      private $prices = array();
      private $images = array();
      private $info = array();
 
    public function __construct()
    {
      parent::__construct();
      $this->_populateModels();
      $this->_populateYears();
      $this->_populatePrices();
      $this->_populateImages();
      $this->_populateInfo();
    }

    ...



Jeg håber det gav lidt mere mening...
Avatar billede wtd_nielsen Nybegynder
20. februar 2010 - 16:38 #4
Man vælger at programmerer op i mod et interface, frem for en implementation, for at feks at skabe lav kobling eller for at kunne behandler nogle klasser på samme måde. Hvis man feks har et program med klasserne Abe, Cat og Horse. Så kunne man definere et interface der hed Speak som har en metoder der hedder makeSound(). Alle dyr implementere dette interface, og har derfor metoden makeSound().

Man kunne så forestille sig at man et sted i sit program havde en metode der så sådan ud:
function doSomething(Speak speaker)
denne metode kan så kaldes med en abe,kat eller hest som parameter, og inde i metoden kalde metoden makeSound.

Man kunne også forestille sig at man havde en abstract klasse der hed Animal, som indeholdt de fælles attributter alle dyr skal have. Dog er Animal klassen så abstrakt og general at den ikke giver mening at kunne oprette objekter af klassen. Man kunne feks også have endnu en abstrakt klasse der hed Bird, som så havde attributter som specielt er for fugle. Dvs at en Måge klasse ville extende Bird klassen, og Bird klassen ville extende Animal klassen. En måge IS-A (er en) Fugl og en fugl IS-A animal.

Hvis man vil sikre sig at en metode ikke kan overskrives, så kan man anvende final. Man kan også bruge final til attributter, hvilket betyder at så snart attributten har fået tildelt en værdi, så kan attributtens værdi ikke ændres.

hvis du virkelig vil lære oop så gå i gang med Java eller C#..synes hele brugen af oop giver mere mening i et "rigtigt" programmeringssprog ;) men det har selvfølgelig også mening i php
Avatar billede j-e Nybegynder
20. februar 2010 - 17:30 #5
Så Interfaces er en skabelon af hvilken metoder en klasse skal indeholde?

En abstrakt klasse er det samme som interfaces bare at den også indeholde nogle standard metoder (standard funktionalitet) som bliver arvet?

Er det rigtigt forstået?
Avatar billede repox Seniormester
20. februar 2010 - 17:43 #6
Nej, en abstrakt klasse er ikke det samme som interfaces.
En klasse kan kan implementere et interface, men en klasse kan dog nedarve flere abstrakte klasser.

Et interface kan heller ikke indeholde variabler eller metoder som kan tilgås. Abstrakte klasser kan indeholde begge dele og man kan arbejde med dem.

Interface metoder kan heller ikke tilgås hverken direkte eller via late binding (da det i øvrigt heller ikke giver mening i forhold til at et interface ikke kan indeholde hverken metoder eller variabler).

Altså, et interface fortæller en udvikler, ved at implementere interfacet, at han skal følge de metodeangivelser der er erklæret. En klasse kan kun implementere et interface.

En abstrakt klasse kan nedarves over flere led og kan tilføje funktionalitet og variabler til klassens øvrige behov, samtidig med at den kan fortælle en udvikler at denne skal huske at lave en specific funktion.
Avatar billede j-e Nybegynder
20. februar 2010 - 20:09 #7
Mange tak begge to :) Nu har jeg da forstået meningen med disse tre ting i oop..

Nu skal jeg nok bare se nogle flere eksempler på anvendelse af oop så jeg kan begynde at lave lidt flere koder selv i oop.

Har nu lige et spørgsmål til slut. Hvis man f.eks. har disse klasser forum, nyheder og gæstebog. Skal man så laver en fælles klasse som de arver database funktioner fra eller skal disse laves for den enkelte klasser. 

Eks 1

class database

{
function connect()  {  } 
function disconnect()    {  } 
function select($table,$rows,$where,$order)        {  } 
function insert($table,$values,$rows)        {  } 
function delete($table,$where)        {  } 
function update($table,$rows,$where)    {  } 
}

class brugere extends database
{

}

class nyheder extends database
{

}

class gæstebog extends database
{

}

eks 2

class brugere
{
function connect()  {  } 
function disconnect()    {  } 
function select()        {  } 
function insert()        {  } 
function delete()        {  } 
function update()    {  } 
}

class nyheder
{
function connect()  {  } 
function disconnect()    {  } 
function select()        {  } 
function insert()        {  } 
function delete()        {  } 
function update()    {  } 
}

class gæstebog
{
function connect()  {  } 
function disconnect()    {  } 
function select()        {  } 
function insert()        {  } 
function delete()        {  } 
function update()    {  } 
}

Hvad gør man normalt?
Avatar billede repox Seniormester
20. februar 2010 - 20:26 #8
Eksempel nummer et ville være den mest optimale.
Eksempel nummer to vil være utænkelig.

Men spørgsmålet er om du i eksempel et overhovedet vil få nogle fordele i at nedarve databaselaget - umiddelbart vil dit databaselag blot være et abstraktionslag; altså, din tilgang til den måde du vil kommunikere med databasen på, fremfor den måde som PHP gør det normalt.

Det vil give mening hvis du havde en klasse der havde nogle generiske funktioner i forhold til de respektive underklasser.
Avatar billede j-e Nybegynder
20. februar 2010 - 20:43 #9
Jeg er ikke helt med på hvad du mener. Skal jeg gøre sådan her.

class database

{
function connect()  {  }
function disconnect()    {  }
function select($table,$rows,$where,$order)        {  }
function insert($table,$values,$rows)        {  }
function delete($table,$where)        {  }
function update($table,$rows,$where)    {  }
}

class brugere
{

}

class nyheder
{

}

class gæstebog
{

}
Avatar billede repox Seniormester
20. februar 2010 - 21:13 #10
Ja, det ville da umiddelbart give mere mening...
Men det er svært at give et kvalificeret bud på at refaktorere din kode ud fra de sparsommelige stumper kode...
Avatar billede j-e Nybegynder
20. februar 2010 - 23:11 #11
Okay jeg prøver lige igen.

Jeg ønsker at lave disse to ting. En gæstebog og et nyhedssystem.

I begge to skal man kunne oprette forbindelse til databasen, oprettet et nyt indlæg, slette et indlæg, opdatere et indlæg.

Hvordan skulle man bygge dette mest optimalt i oop med hensyn til klasser og metoder?
Avatar billede j-e Nybegynder
20. februar 2010 - 23:13 #12
Udover dette skal de også have nogle metoder som er individuelle.
Avatar billede zynzz Praktikant
21. februar 2010 - 00:49 #13
Jeg kalder min database i constructoren...

class Nyheder
{
    private $Database;

    public function __construct()
    {
        $this->Database = new Mysql();
    }
}

Så kan du bruge funktionerne fra Mysql klassen vha. $this->Database->Funktion() i din klasse...
Avatar billede wtd_nielsen Nybegynder
21. februar 2010 - 11:38 #14
jeg vil mene at det er ret tungt at oprette en databaseforbindelse og du bør lave en Database-klasse som følger Singleton design pattern. se:
http://en.wikipedia.org/wiki/Singleton_pattern

Med Singleton oprettes der kun een instans af objektet, da man ikke har behov for at der skal oprettes flere end et objekt af klassen.

Så feks i Nyheder klassen, kalder du $this->database = Database::getInstance();
Avatar billede repox Seniormester
21. februar 2010 - 13:15 #15
Som #13 er inde på, kan du få et fornuftigt setup i at dele databaselaget op i sin egen klasse, fremfor at udvide dine funktionelle klasser med databaselaget.

Selvom #14 taler for at implementere et design pattern, så vil jeg mene du skal lægge det på hylden til du har fået mere kontrol over din OOP.
At forstå og implementere et reelt design pattern kræver en portion erfaring med OOP. Man kan selvfølgelig bare klippe-klistre fra nogle eksempler, men du skal også forstå hvad der bliver gjort for at kunne bruge det til noget.

Udover det, så kører MySQL i sin egen process og deler ikke resourcer med PHP; så optimering med henblik på MySQL vil hurtigst kunne findes i dine SQL sætninger - ikke i antallet af instanser af dit database lag.

Men når du har fået lavet nogle konkrete klasser som du anvender, kan det være der du skal overveje at studere design patterns specifikt til PHP (for PHP er et klytsprog, særligt i forhold til OOP) og så derefter refaktorere din kode...
Avatar billede j-e Nybegynder
21. februar 2010 - 14:47 #16
#13 Er ikke helt med på hvad du mener. Men jeg forstår det sådan her..

class Database
{

    function mysql()
    {
        //Opret forbindelse til database.
    }
}

class Nyheder
{
    private $Database;

    function __construct()
    {
        $this->Database = new Mysql();
    }
    function select()        {  }
    function insert()        {  }
    function delete()        {  }
    function update()    {  }

}
Er det korrekt?
---
#14 Jeg kan ikke helt forstå hvad det gøre godt for. Men kan godt cirka forstå hvad det er som sker i eksemplet på wiki..
----
#15 Jeg er bare ikke helt med på hvad han mener jeg skal gøre i #13.. Jeg tror også det omtalte emne i #14 er lige lidt for svært lige nu for mig.

Ja det kan godt være jeg skal læse noget om det der design patterns når jeg har forstået php oop lidt bedre.. Lige nu er jeg bare interesseret i at forstå grundtanke bag oop i php så jeg kan udnytte fordelene ved det når jeg koder.
Avatar billede repox Seniormester
21. februar 2010 - 15:24 #17
Hvis du ikke helt kan forstå konceptet bag et databaseabstraktionslag, så må du gemme det til senere. Så koncentrer dig om at lære og forstå anvendelsen af abstrakte klasser, nedarvning og polymorfi.

Jeg har skrevet en slags introduktionsartikel om emnet, som du kan finde her: http://err0r.dk/articles/read/hvad_er_oop

Udover det, kan det også betale sig at lave nogle færdige scripts, som du har fået til at virke og så spørge her i forummet igen hvad brugerne synes om det du har lavet; husk på at programmering ikke har en facitliste; der findes ikke én korrekt løsning på et givet problem, men mange.
Avatar billede j-e Nybegynder
21. februar 2010 - 15:37 #18
Nej jeg forstår ikke helt konceptet bag et databaseabstraktionslag, men har forstået abstrakte klasser, nedarvning og polymorfi. Har også læst din fine artikel på http://err0r.dk/articles/read/hvad_er_oop..

Jeg vil også rigtigt gerne i gang med at lave noget, men så lang tid jeg ikke ved hvordan jeg skal bruge en database i oop, så synes jeg det er lidt svært at lave en helt masse.
Avatar billede repox Seniormester
21. februar 2010 - 16:05 #19
Du kan prøve at se det abstraktionslag jeg selv anvender til mine MySQL kald: http://codepad.org/8RQbRKcr

Idéen er at jeg i en config fil (som jo altid er inkluderet i koden) har angivet konstanterne SQL_BASEHOST, SQL_USERNAME, SQL_PASSWORD og SQL_DATABASE med de (forhåbentligt selvforklarende) værdier som jeg anvender til at forbinde til databasen.

Jeg anvender dog et kombineret design pattern (factory og singleton) til at instansiere mit databaseabstraktionslag, men det behøver du ikke for at kunne anvende den.

Det er ret simpelt, når databaseabstraktionslaget først er inkluderet i koden:

<?php

 
  class Users
  {
      private $db;
     
      public function __construct()
      {
          $this->db = new Mysql();
      }
     
      public function login( $username, $password )
      {
          $username = $this->db->escape($username);
          $password = MD5($password);
         
          $sql = "SELECT userId FROM users WHERE username='".$username."' AND password='".$password."' LIMIT 1":
          $userId = $this->db->queryItem($sql);
     
          return $userId;
     
      }
     
        ...     
     
  }

?>


Der er ikke så meget forklaring til Mysql klassen, da jeg selv bruger den og havde ikke brug for at dokumentere den. Det var også blot for at give dig en idé om hvordan det fungerer med et databaseabstraktionslag.
Avatar billede zynzz Praktikant
21. februar 2010 - 16:19 #20
Som fremgår af min og repox`s (#19) kommentar, så får du tilgang til alle funktionerne fra mysql klassen ved at kalde denne klasse...
Avatar billede j-e Nybegynder
21. februar 2010 - 23:41 #21
Jeg forstår godt det meste af mysql klassen og synes det er mega smart. :) Der er gået et lille lys op for mig tror jeg.. Jeg er dog ikke helt med på hvad du mener med "
Jeg anvender dog et kombineret design pattern (factory og singleton) til at instansiere mit databaseabstraktionslag, men det behøver du ikke for at kunne anvende den." Men det lyder da interessant.. Fandt også lige dette her http://net.tutsplus.com/tutorials/php/real-world-oop-with-php-and-mysql/ det virker som lidt at det samme som din mysql klasse... Så det vil jeg til at se lidt på.. Ellers må jeg bare i gang med at lege.. Men mange tak for hjælpen. Kan i ikke smide et svar så jeg kan få afgivet point. Jeg ved dog ikke hvordan min fordeling af disse skal være.. :)
Avatar billede repox Seniormester
22. februar 2010 - 08:37 #22
Det jeg mener med at jeg anvender et kombineret design pattern er at jeg har valgt at få to design patterns til at arbejde sammen, for at give mig mit ønskede resultat. Factory pattern til at finde og instanciere mit objekt, singleton pattern til at sikre mig at jeg kun får en enkelt instans (dog den samme) returneret gennem hele koden.

Det betyder at jeg instansierer mine objekter således:

  $db = cCore::getResource("Databases.Mysql");


Såfremt jeg allerede har instansieret objektet en gang, får jeg det samme objekt retur.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester