OOP-exempel - Fibonacci

I denna artikeln visar vi exempel på hur man kan använda en klass för att räkna ut fibonaccis talföljd.

En känd talföljd är fibonaccis talföljd. De två första talen i denna talföljden är 1, och nästkommande tal räknas ut genom att addera de två föregående talen i talföljden. Så när vi ska räkna ut de 10 första talen blir de så här:

Kod - Random Kod
1, 1, 1 1, 1, 2 1, 1, 2, 3 1, 1, 2, 3, 5 1, 1, 2, 3, 5, 8 1, 1, 2, 3, 5, 8, 13 1, 1, 2, 3, 5, 8, 13, 21 1, 1, 2, 3, 5, 8, 13, 21, 34 1, 1, 2, 3, 5, 8, 13, 21, 34, 55

Antag att vi vill skriva en kod som visar de 10 första talen i fibonaccis talföljd i en lista. Ett första försök (utan OOP) skulle kunna se ut så här:

PHP - PHP: Hypertext Preprocessor
<?php echo "<ul>\n"; // Nuvarande och föregående tal i talföljden $föregående = 0; $nuvarande = 1; // Iterera 10 gånger for($i=1; $i<=10; $i++){ // Skriv ut nuvarande... echo "\t<li>$nuvarande</li>\n"; // ...och beräkna nästa $temp = $nuvarande; $nuvarande += $föregående; $föregående = $temp; } echo '</ul>'; ?>
HTML - HyperText Markup Language
<ul> <li>1</li> <li>1</li> <li>2</li> <li>3</li> <li>5</li> <li>8</li> <li>13</li> <li>21</li> <li>34</li> <li>55</li> </ul>
  • 1
  • 1
  • 2
  • 3
  • 5
  • 8
  • 13
  • 21
  • 34
  • 55

Det här var ju inte jättesvårt, kan OOP verkligen lösa det här på ett bättre sätt? Vad kan göras bättre egentligen? Jo, vi behöver ju någonstans ha koden som beräknar nästa tal i talföljden, och den ligger just nu i loopen. Visserligen rör det sig bara om 3 rader (raderna 16-18), men i andra fall kan det vara mycket mer komplicerade uträkningar som behövs göras, och att lägga dem på ett eget ställe i koden (förslagsvis i en egen funktion) gör koden lättare att läsa.

Problemet är att vi till denna funktionen ska skicka in 2 argument ($föregående och $nuvarande) och få tillbaka 2 värden (de nya talen i $föregående och $nuvarande), men en funktion kan bara ha ett returvärde. Går det att lösa? Jo, med en associativ array går det faktiskt att åstadkomma:

PHP - PHP: Hypertext Preprocessor
<?php echo "<ul>\n"; // Nuvarande och föregående tal i talföljden $talen = array('föregående' => 0, 'nuvarande' => 1); // Funktion som returnerar nästa fibonacci-tal function nästaFibonacci($talen){ $temp = $talen['nuvarande']; $talen['nuvarande'] += $talen['föregående']; $talen['föregående'] = $temp; return $talen; } // Iterera 10 gånger for($i=1; $i<=10; $i++){ // Skriv ut nuvarande... echo "\t<li>{$talen['nuvarande']}</li>\n"; // ...och beräkna nästa $talen = nästaFibonacci($talen); } echo '</ul>'; ?>

Nu har vi lyckats få bort uträkningen av nästa fibonacci-tal från loopen, och koden blir enklare att läsa. Den här lösning är väldigt likt den vi kommer få med hjälp av OOP, men en nackdel vi har här är att vi använder en associativ array. Eller, nackdel och nackdel, det är inget fel med att använda associativ arrayer, men de som använder den här koden måste veta att fibonacci-talen representeras med hjälp av en associativ array. Med OOP kan vi dölja implementationen, och de som använder sig av koden behöver inte oroa sig för det.

Men nu över till hur vi löser det med hjälp av OOP. Lösningen är inte så komplicerad, så vi skriver den bara rätt upp och ner.

class Fibonacciuträknare{ private $föregående; private $nuvarande; public function __construct(){ $this->föregående = 0; $this->nuvarande = 1; } public function hämtaNuvarande(){ return $this->nuvarande; } public function gåTillNästa(){ $temp = $this->nuvarande; $this->nuvarande += $this->föregående $this->föregående = $temp; } }
PHP - PHP: Hypertext Preprocessor
<?php // Inkludera klassen include_once 'Fibonacciuträknare.php'; $fibonacci = new FibonacciUträknare(); // Iterera 10 gånger for($i=1; $i<=10; $i++){ // Skriv ut nuvarande... echo "\t<li>".$fibonacci->hämtaNuvarande()."</li>\n"; // ...och beräkna nästa $fibonacci->beräknaNästa(); } ?>

Första vinsten med denna lösningen jämt emot förra är att vi inte behöver ange början på fibonacci-serien på rad 6, eftersom konstruktorn i klassen gör det åt oss. Andra vinsten är att vi inte behöver veta hur lösningen är implementerad, vi behöver bara veta hur vi ska anropa de funktioner som har synligheten public i klassen. När man tänker efter behöver de som använder klassen inte ens veta vad fibonaccis talföljd är, de kan använda klassen i alla fall. Får de till exempel uppgiften "Skriv ut de 10 första talen i fibonaccis talföljd" så kan de lösa uppgiften genom att använda sig av denna klassen utan att ens förstå hur fibonaccis talföljd fungerar. Detta är en väldigt stor styrka som OOP värdesätter högt - de som använder sig av klasser behöver inte veta hur de fungerar, bara hur man använder dem.

Om man får uppgiften "Skriv ut de 10 första talen i fibonaccis talföljd" och har tillgång till klassen Fibonacciuträknare, kan man lösa uppgiften på ett bättre sätt än det vi gjort ovan? Eftersom koden nu är så liten och lättförståelig kan man troligtvis inte göra det, men man kan lösa det på ett annat sätt genom att låta klassen ha reda på hur många fibonaccinummer den har räknat ut. Just nu har ju $i i loopen reda på det, men om klassen istället håller koll på det blir koden ännu mindre (dock växer koden i klassen). Vi kan implementera denna funktionaliteten i en ny klass som ärver från klassen vi har nu.

PHP - PHP: Hypertext Preprocessor
<?php // Inkludera klassen include_once 'Fibonacciuträknare'; class RäknandeFibonacciuträknare extends Fibonacciuträknare{ private $räknare; public function __construct(){ parent::__construct(); $this->räknare = 1; } public function gåTillNästa(){ parent::gåTillNästa(); $this->räknare++; } public function hämtaNuvarandeIndex(){ return $this->räknare; } } ?>
PHP - PHP: Hypertext Preprocessor
<?php // Inkludera klassen include_once 'RäknandeFibonacciuträknare.php'; $fibonacci = new RäknandeFibonacciUträknare(); // Iterera 10 gånger while($fibonacci->hämtaNuvarandeIndex() <= 10){ // Skriv ut nuvarande... echo "\t<li>".$fibonacci->hämtaNuvarande()."</li>\n"; // ...och beräkna nästa $fibonacci->beräknaNästa(); } ?>

Vi har gått från en for-loop till en while-loop, vilken är enklare till sin struktur, men frågan är om vi har vunnit något på det i det här fallet.