2016-05-18 4 views
4

Ich habe eine große Klasse (1500 Zeilen, aber wird bald mehrere Male sein), die ich möchte, dass es besser passt mit SRP (und so dass jede Datei kleiner und überschaubar ist .)Splitting eine große PHP-Klasse

die Klasse enthält 50-100 Eigenschaften, und verschiedene Arten von Aktionen, die gegen sie durchgeführt werden, hat - von denen ein update sein würde, die mehrere Schritte wiederum tut wie die Datenbank aktualisieren, und E-Mails senden.

Also ich denke, ich möchte 4 Klassen.

Wie soll ich die Klassen strukturieren?


Hier ist eine vereinfachte Version von dem, was ich habe jetzt:

class Foo { 
    public function __construct ($params) {} 

    public function update() { 
     $this->updateDatabase(); 
     $this->sendEmails(); 
    } 

    private function updateDatabase() {} 
    private function sendEmails() {} 
} 

$foo = new Foo($params); 
$foo->update(); 

updateDatabase() und sendEmails() jeder Aufruf viele andere Methoden - Hunderte von Zeilen Code jeder, und sie haben mehrere Geschwister Methoden andere Aufgaben.

Eine grundlegende Rewrite statische Methoden

class Foo { 
    public function __construct ($params) {} 
} 

class FooUpdate { 
    public static function update ($fooParam) { 
     FooUpdateDatabase::main($fooParam); 
     FooSendEmails::main($fooParam); 
    } 
} 

class FooUpdateDatabase { 
    public static function main ($fooParam) {} 
} 

class FooSendEmails { 
    public static function main ($fooParam) {} 
} 

$foo = new Foo($params); 
FooUpdate::update($foo); 

Eine grundlegende Rewrite verwenden

class Foo { 
    public function __construct() {} 
} 

class FooUpdate { 
    private $foo; 
    public function __construct ($fooParam) { 
     $this->foo = $fooParam; 
    } 
    public function main() { 
     $fooTemp = FooUpdateDatabase($this->fooParam); 
     $fooTemp->main(); 
     $fooTemp = FooSendEmails($this->fooParam); 
     $fooTemp->main(); 
    } 
} 

class FooUpdateDatabase { 
    private $foo; 
    public function __construct ($fooParam) { 
     $this->foo = $fooParam; 
    } 
    public function main() {} 
} 

class FooSendEmails { 
    private $foo; 
    public function __construct ($fooParam) { 
     $this->foo = $fooParam; 
    } 
    public function main() {} 
} 

$foo = new Foo($bar, ...); 
$fooTemp = new FooUpdate($foo); 
$fooTemp->update(); 

instanzierte Objekte zu verwenden, Oder sollte ich Vererbung oder irgendwie Züge?

+2

Sie würden das meiste (passende) Feedback bei [Code Review] (http://codereview.stackexchange.com/) bekommen. Ich denke nach. – Marcus

+1

@Marcus Bitte beachten Sie, dass Foo/Bar-Kennungen eine unangemessene Code Review-Frage machen würden. –

+0

@ 200_success Guter Punkt. Damit sehe ich diese Frage sehr auf der Grundlage von Meinungen. – Marcus

Antwort

2

Ich denke, das Senden von E-Mails ist eine Sache, die Ihre Daten repräsentieren ist eine andere und Lese-Schreib-Operationen in der Datenbank wäre ein drittes.

Also class Foo, class FooPersistence, class FooMailer.
Und wer ruft die FooPersistence::update($foo) sollte auch FooMailer::sendUpdateNotification($foo) anrufen.

Als Randbemerkung:
Wenn Sie so etwas wie Ereignisse haben einrichten würde ich das „Update-Event“ in der Ausdauer Klasse auslösen und einen Hörer, um es hinzuzufügen, die E-Mails sendet.

+1

@Redzarf Ich werde es hier als Kommentar hinterlassen, weil es nicht wirklich Teil der Antwort noch das Hauptthema der Frage ist, sondern eine Ergänzung der Randnotiz: https://github.com/SparK-Cruz/elpho/ blob/master/samples/events/Events.php – SparK

2

Wie @SparK sagt

  • Ihr Objekt (Foo)
  • Eine Klasse, die die Datenbankkommunikation (FooRepository)
  • A-Klasse behandelt, die Mails (Mailer)
  • Eine Klasse sendet, wickelt es alle (FooManager)

    $foo = new Foo($params); 
    $fooManager = new FooManager(FooRepository, Mailer); 
    $fooManager->update($foo); 
    $fooManager->notify($foo); //this could be inside the update or an event. 
    

Auf diese Weise können Sie auch Ihre Klassen zerlegen (dh eine Klasse trennen, die Datenbankverbindungen verarbeitet und sie in das FooRepository einschleusen usw.). Aber ich glaube nicht, dass Klassen, die eine Aktion darstellen, der richtige Weg sind?

Klassen sind Objekte, die unter anderem Aktionen ausführen können, nicht Aktionen (dies ist nur ein Kommentar wegen der Namen, die Sie in Ihrem Beispiel verwendet haben: p).

+0

Danke, ich denke, die Manager-Klasse ist das Konzept, über das ich mehr lesen muss. Können Sie Ihre zweite Codezeile erklären? Oder ist es eine Abkürzung für '$ fooRepository = new FooRepository(); $ mailer = new Mailer(); $ fooManager = neuer FooManager ($ fooRepository, $ mailer); ' – Redzarf

+0

Gibt es irgendeinen Grund, eine Instanz von' FooManager' zu erstellen, anstatt nur statische Methoden zu verwenden (da '$ foo' als Parameter übergeben wird) sowieso). – Redzarf

+0

@Redzarf Ja, nur eine Kurzschrift. Sie könnten aber auch Interfaces anstelle dieser Klassen (zB: MailerInterface) in der Konstruktordefinition von FooManager übergeben. Wenn Sie es erstellen, müssen Sie ein Mailer-Objekt übergeben, das diese Schnittstelle implementiert. Das ist nützlich, wenn Ihre App wächst und andere daran arbeiten. --- Wenn der FooManager über statische Methoden verfügt, werden Sie das FooRepository und den Mailer übergeben. Sie können sie in den statischen Funktionen erstellen, aber ich sehe keinen Grund dafür, vielleicht liege ich falsch. Wenn ein anderes Objekt einen FooManager verwenden muss, können Sie es einfach injizieren. – Blitu