Permalänk
Medlem

Programmeringsdesign, PHP

Har ett problem som jag har svårt att implementera på ett snyggt sätt. Jag har redan en implementation, och även fast den fungerar, så är jag inte riktigt nöjd med den rent programmeringsmässigt. Det känns som att det finns ett snyggare sätt att göra det.

Bakgrund:
Jag driver en form av en annonssajt. Spelar inte riktigt roll vad det är, men följande information är tillgänglig. Problemet jag har är att jag försöker skapa en listningsmodul som listar alla givna (till modulen givna) annonser på ett lämpligt sätt.

Användaren kan ha tre olika tillgångsnivåer; Besökare, Ägare och Administratör.
Utöver detta kan varje Annons vara antingen Aktiv, Inaktiv eller Pausad.

Funktion
Modulen ska ta emot en lista med annonser och lista dessa på ett lämpligt sätt. Anledningen till att jag vill baka ihop allting till en modul är att listningen i stort är identisk, förutom smärre variationer. Det känns därmed dumt att upprätthålla flera olika versioner (om jag ändrar på ett ställe är jag tvungen att ändra på flera ställen).

Baserat på vilken kombination av ovanstående, ska olika saker visas.

Om det är en Besökare som listar en Pausad annons = en vy.
Om det är en Ägare som listar en Aktiv annons = en annan vy.
Om det är en Administratör som listar en Pausad annons = en annan vy osv osv.

Hur gör jag detta på ett snyggt objekt orienterat sätt? I största mån vill jag undvika kluster av if-satser och duplikation. Jag använder mig utav PHP, så multiple inheritance är inte ett alternativ.

Förslag? Min magkänsla säger att detta bör gå att lösa på ett snyggt sätt med typ polymorfism.

Visa signatur

Let me tell you something. You don't have to say anything, you know why? Cause you can pick up all your stuff, because you're mother-fucking fired! | Lemeno.se - En blogg om att Tjäna Pengar På Internet | Min blogg om styrketräning och kost

Permalänk
Medlem

Det är alltid svårt att uttrycka sig kärnfullt men ändå klart när det gäller programmering tycker jag.

Egentligen är det jag försöker komma undan en följande konstruktion med upprepade if-satser:

class Ad { public $adState = 'active'; } class AdWriter { public function displayAd(Ad $ad, $viewmode = 'visitor') { if ($viewmode =='visitor') { if ($adState == 'active') {} else if ($adState == 'paused') {} else if ($adState == 'inactive') {} } else if ($viewmode = 'owner') { if ($adState == 'active') {} else if ($adState == 'paused') {} else if ($adState == 'inactive') {} } else if ($viewmode == 'administrator') { if ($adState == 'active') {} else if ($adState == 'paused') {} else if ($adState == 'inactive') {} } } }

Går det att komma undan på något sätt? Visserligen visar alla varianterna av if-satserna olika saker, men som tidigare nämnt känns det som att det går att lösa på ett snyggare sätt.

Visa signatur

Let me tell you something. You don't have to say anything, you know why? Cause you can pick up all your stuff, because you're mother-fucking fired! | Lemeno.se - En blogg om att Tjäna Pengar På Internet | Min blogg om styrketräning och kost

Permalänk
Medlem

Här är ett exempel på hur du undviker upprepade if/else. Tycker switch blir lite tydligare i exemplet men den fungerar egentligen som if/else så det är inte direkt någon superfördel.

class ad{ const active = 1; const paused = 2; const inactive = 3; const visitor = 1; const owner = 2; const administrator = 3; public $adState = self::active; } class AdWrite{ function displayAd(Ad $ad, $viewmode = ad::visitor) { switch($viewmode){ case ad::visitor: $this->view_visitor_stuff($ad); break; case ad::owner; $this->view_owner_stuff($ad); break; case ad::administrator; $this->view_admin_stuff($ad); break; default: throw new exception("Incorrect viewmode"); break; } $this->common_ad_view($ad); } function view_administrator_stuff(Ad $ad){ /* Ex. en header med lite länkar till "edit ad", "remove ad", "view users other ads", osv. */ echo $ad->some_adminspecific_options; } function view_owner_stuff(Ad $ad){ /* Ex. lite "view other ads I own", "edit this ad", etc. */ echo $ad->owner_stuff; } function view_visitor_stuff(Ad $ad){ /* Kanske inte så mycket som en besökare ser som ingen annan ser... */ } function common_ad_view(Ad $ad){ /* Relevant för alla, ex. hur reklamen ser/såg ut */ echo $ad->stuff_common_for_all_ads; } }

Men det verkar ju som att du har massa typiska if/else-grejer så det kan bli svårt att undvika. Du måste förr eller senare handskas med "Om det är en besökare, visa det här. Om det är admin, visa det här!" Om du väljer att göra det med olika funktioner som i mitt exempel, eller i en view-funktion typ:

function view(Ad $ad, $viewmode){ if($viewmode == ad::administrator){ echo "Stäng av användarens reklam"; }elseif($viewmode == ad::owner){ echo "Ta bort reklam"; }elseif($viewmode == ad::visitor){ /* Kommer inte på något exempel */ } echo $ad->some_ad_property; }

Är nog lite upp till hur du tycker känns enklast. En stor view-funktion blir snabbt krånglig att underhålla.

Ett annat alternativ är att ex. ge "Ad" en egen "access-mode" och __get funktion, ex:

class ad{ /* Samma consts som ovan */ private $access; private $adproperties; function set_access($new_access){ switch($new_access){ case self::administrator: $this->access = self::administrator; break; /* Samma som ovan och exception på default */ } } function __get($name){ $owner_properties = array("some_owner_key"); $admin_properties = array("ad_database_id", "other_admin_keys"); if(array_key_exists($name, $this->adproperties){ if(in_array($name, $owner_properties)) { if($this->access === self::owner || $this->access === self::administrator) { return $this->adproperties[$name]; }else{ /* Exception eller false, beroende på hur du väljer att använda funktionen kanske */ throw new exception("Insufficient rights"); } } elseif(in_array($name, $admin_properties)){ if($this->access === self::administrator) { return $this->adproperties[$name]; }/*Else some ovan */ } return $this->adproperteis[$name]; }else{ throw new exception("Incorrect name"); } } }

Funktionen ovan går bra med en gemensam view_ad funktion i AdWrite för då kan du jämföra med false eller köra try/catch-block så går den igenom allt automatiskt.

Abstraction ftw, fast nu ska jag inte flumma mer!

Visa signatur

Cat funeral! Cat funeral!
>>> 112383 <<<