OOP kavramlarını basit ama gerçek dünyaya ait bir web uygulaması oluşturmak için nasıl uygulayabilirim? [kapalı]


25

Uzun zamandır kafamı OOP'a sarmaya çalışıyorum. Avantajlarını görüyorum. Çok, çok sayıda öğretici okudum ve konuyla ilgili eşit miktarda video izledim. Hayvan / kedi / köpek örneklerini alıyorum, araba / sürücü örneklerini alıyorum. Uğraştığım şey, bu kavramları gerçek dünyadaki bir uygulamada nasıl uygulayacağım. Böylece, OOP kullanarak bir tane inşa etmeye başladım.

Sözdizimi konusunda yardım istemiyorum ya da özel kod yazmıyorum - kendimi belgelerde bulabilirim ve forumlar vb. Arayarak bulabilirim. Gerçekten ihtiyacım olan biraz rehberlik ve her zaman doğru yöne doğru itmek. Bana rehberlik etmek isteyen deneyimli programcılar var mı?

Öğrenme projem olarak basit ilanlar "web uygulaması" oluşturmak istiyorum. Craigslist'e benzeyen ancak kapsam bakımından sulanan bir şey. PHP5 ve MySQL kullanmak istiyorum, çünkü onlara aşinayım.

Diyelim ki sadece bu 2 kullanım durumu var:

  1. Satılık bir şey yayınlamak
  2. Satın almak için bir şeyler aramak / aramak

Nesneler ne olmalı? Her maddenin bir nesne olabileceğini hayal edebiliyorum, ama hangi noktada? Ve neden?

Örneğin, kullanıcı "satış için satış kalemi" formunu doldurur, bu form değerleri bir veritabanına ekleyen başka bir nesneye geçen bir nesneye dönüşür mü?

Peki ya başka bir kullanıcı tarama yapıyorsa ve C kategorisinin tüm öğelerini görmek isterse? Uygulama veritabanına bağlanmak zorunda kaldığında bir veritabanı nesnesi oluşturup daha sonra bir sürü öğe nesnesi alıp bunları sayfada göstermesi mantıklı geliyor mu? … Bunu yazmam kesinlikle ne kadar ipucum olmadığını hala OOP konusunda olduğumu anlamamı sağlıyor. Lütfen bunu düzeltmeme yardım et.

Sizce bu, OOP'a girmeye başlamak için iyi bir proje değilse, lütfen başka bir fikir önermek için çekinmeyin!


1
Aynı teknedeyim, sanırım OOP'u anlıyorum - Java'yı denediğimden bu yana bir süre geçti, fakat PHP'ye gelince bu gibi şeyleri nasıl anında 'normal' şekilde yapabileceğimi biliyorum ama bunun nasıl olacağını OOP kullanılarak yapılacaktı yaşama isteğimi yitiriyorum.
martincarlin87 16:12

Form bir nesneye dönüşmedi. Bir nesne sınıfın bir örneğidir. Bunu böyle görebiliyordun. $ item-> saveItem ($ _ POST ['isim'], $ _POST ['açıklama']); düzenleme Gerçekten ne yardımcı oldu OOP bulmak basit bir "ziyaretçi defteri" web uygulaması yaratıyor. Kullanıcıların giriş yapmalarını, mesaj gönderme, mesajları düzenleme, mesajları silme ve mesajları arama vs.

@pduersteler iyi fikir, bunu nasıl yapacağım? Kuşkusuz, bu stackoverflow hakkındaki ilk sorum :)

@Bono belki de bahsettiğiniz gibi bir ziyaretçi defteri uygulaması gerçekten başlamak için daha iyi bir yer. Düşündüğüm diğeri ise kullanıcıların giriş yaptıkları, listeler düzenledikleri / sildikleri, listelerindeki öğeleri ekledikleri / düzenledikleri / sildikleri çok basit bir liste uygulamasıydı. Ziyaretçi defteri uygulamanızı bizimle / benimle paylaşır mısınız?

Bunu paylaşırken sakıncası olmaz, ancak postalamak için bir kod loooot olurdu. İsterseniz basit bir örnek sınıfı sizinle paylaşabilirim. Ayrıca bu kodun ne kadar iyi çalışacağını da bilmiyorum, çünkü açıkçası bir süre oldu: P aşağıda yazacağım

Yanıtlar:


17

Dürüst olmak gerekirse, bu tavsiyenin şu ana kadar yeni OO öğrencileri için korkunç olduğunu düşünüyorum. Nesneleri, bir sınıf tarafından tanımlanan "şey" in belirli bir örneğinin temsili olarak düşünmeye hemen başlamak iyi bir fikir değildir. Bunları, birbirleriyle etkileşime giren, ancak birbirlerinin içindekileri olmayan, makinenin bölümlendirilmiş bileşenleri olarak düşünmek daha iyidir. Bu bileşenlerin her biri durumu korur

DB etkileşimleri için bir ORM (nesne-ilişkisel eşleme) kullanmak istiyorsanız, kullandığınız veya oluşturduğunuz çerçevede muhtemelen tabloları temsil eden bazı sığ nesneler olacaktır, bunlar muhtemelen "şeylerin" koleksiyonudur, ancak kişisel olarak ORM'leri sevmem ve mutlaka ideal OO uygulamalarını temsil ettiklerini sanmıyorum, ancak büyük web uygulamaları için popüler.

Bunun yanı sıra, muhtemelen web uygulama makinesinin bir veya daha fazla DB bağlantısı gibi çalışması gereken bazı önemli bileşenlere sahip olacaksınız (bir bağlantıyı koruyan bir sınıf oluşturabilir ve hazırlanmış sorguları çalıştırabilirsiniz - PDOkendi başına mükemmeldir. , ama ben sarım) ve belki de görüşleriniz için bir şablon sistemi. Denetleyicilerinizin de PHP nesneleri olmasını isteyebilirsiniz. Doldurmanız gereken bir form varsa, P / R / G için form değerlerini koruyan, bir CSRF koruma belirteci olan ve girişlerinde doğrulama gerçekleştirebilen bir nesneye sahip olabilirsiniz.

Web uygulaması tasarımınızı ve nesne grafiğinizi oluştururken nesnelere dönüşmek için "şeyler" aramaya çalışmamalısınız. Bunun yerine, bir araya getirmek için bir araya gelen mantıksal bileşenleri düşünmelisiniz. Bunu zorlamaya çalışmanız gerektiğini ve bunun oldukça doğal gelmesi gerektiğini düşünmüyorum, ancak doğru bir şekilde yapmak çok zor ve kesinlikle yol boyunca bazı tasarım kararlarını değiştirmek zorunda kalacaksınız.

Son tavsiyem şudur: miras konusundaki kompozisyon, gidilecek yoldur.


Özellikle dinamik diller için elimde olan bir kural, yalnızca polimorfizmden yararlanmak istiyorsam (yani, eğer bu sınıflar aynı yöntemin farklı versiyonlarını uygulayacaksa ve mantık buna bağlı olacaksa) sınıfları oluşturmaya çalışmaktır. bir şekilde). Aksi takdirde, basit tutmak için daha "usule uygun" bir stilde yazmaya karar veriyorum.
hugomg

9

Evcil hayvanlarınızı satın almak ve satmak için OOP'yi nasıl kullanabileceğinizi öğrenin, aynı metodoloji arabaları veya uçakları satmak için kullanılabilir;

<?php
// define a superclass .. no instances will be made of 'animal' itself,
// but it is useful to define common characteristics and behaviours
// (ie: properties and methods) of all our classes of animals
class Animal {

    // this constructor function is called whenever a new instance
    // of the Animal class is created (or any class that inherits from Animal)
    function Animal ($colour) {

        // install the argument as an attribute of any instances of Animal
        $this->colour = $colour;
    }

    // this method will be available to all classes that inherit from Animal
    function report () {
        return "This ".$this->colour." ".get_class($this)." has ".$this->legs." legs.<br />";
    }
}

// this class inherits from Animal
class Cat extends Animal {

    // set the legs attribute
    public $legs = 4;

    // create a method that can be called from any instances of Cat
    function make_noise () {
        echo "MEOW!<br />";
    }
}

// this class inherits from Cat, and from Animal
class Panther extends Cat {

    // specifies the colour attribute
    public $colour = "black";

    // overwrites the constructor function that would otherwise be
    // inherited from Animal, with a blank constructor.
    function Panther () {}

    // overwrites the method inherited from Cat
    function make_noise () {
        echo "ROARRRR!<br />";
    }
}

// this class inherits from Animal
class Snake extends Animal {
    public $legs = 0;
}

// this class is unrelated to the others
class PetShop {

    // set up an array to store the pets that the shop will stock
    public $pets = array ();

    // set up a variable to store the total cash in the pet shop
    public $cash;

    // this method creates a new object and adds it to the pets array
    function add_pet ($petclass, $price, $colour) {

        // set up a variable containing the number of elements in the pets array
        $n_pets = count($this->pets);

        // add to the pets array, a new instance of the class specified as
        // the first argument in this method, using the last argument as the
        // colour argument that is passed to the specified class's constructor
        $this->pets[$n_pets] = new $petclass($colour);

        // add a 'price' attribute to the pet object
        $this->pets[$n_pets]->price = $price;
    }

    // this method removes the specified pet from the array and adds the price
    // to the pet shop's cash variable
    function sell_pet ($n) {

        // add pet's price to the cash total
        $this->cash += $this->pets[$n]->price;

        // remove the pet object from the array
        array_splice($this->pets, $n, 1);

        // give a message about the sale
        echo "SALE: Pet no. ".$n." sold. Total cash is now \$".$this->cash.".<br /><br />";
    }

    // this method reports on the pet shop's stock
    function show_pets () {

        // show the number of pets available
        echo "<B>Shop stock:</B><br />We have ".count($this->pets)." pets for sale.";
        echo "<br /><br />";

        // iterate through the pets array and show information about each one
        for ($i = 0; $i < count($this->pets); $i++) {
            echo "<B>Pet No. ".$i.": </b>".$this->pets[$i]->report();
            echo "Price: \$".$this->pets[$i]->price."<br />";
        }
        echo "<br />";
    }
}

// instantiate a new PetShop object
$shop = new PetShop ();

// add three pets to the shop
$shop->add_pet(cat, 20, "tabby");
$shop->add_pet(snake, 40, "brown");
$shop->add_pet(snake, 60, "black");

// show the pet's stock
$shop->show_pets();

// sell the first pet in the stock
$shop->sell_pet(0);

// show the pet's stock after the sale
$shop->show_pets();
?>

28
Arabalar veya hayvanlar ile ilgili bir başka örnek görürsem, kaybedeceğim
Neil McGuigan

5

OP'nin isteği üzerine ziyaretçi defteri kodumu paylaşacağım.
Mesaj sınıfı:

<?php 
Class message
{
    private $db;
    private $messageID;
    private $message;
    private $name;
    private $mail;

    public function setmessageID($messageID)
    {
        $this->messageID = $messageID;
    }

    public function getmessageID()
    {
        return $this->messageID;
    }

    public function setmessage($message)
    {
        $this->message = $message;
    }

    public function getmessage()
    {
        return $this->message;
    }

    public function setname($name)
    {
        $this->name = $name;
    }

    public function getname()
    {
        return $this->name;
    }

    public function setMail($mail)
    {
        $this->mail = $mail;
    }

    public function getMail()
    {
        return $this->mail;
    }
}

Mesaj Veri Erişim Nesne Sınıfı:

<?php 
class messageDAO
{
    private $db;
    private $aantalMessages;
    private $messages;
    private $message;

    //bij laden roept hij automatisch Db class aan (en de daarbij gezeten functies)
    public function __construct(Db $db)
    {
        $this->db = $db;
    }

    public function getMessages()
    {
        return $this->messages;
    }

    public function getAantalMessages()
    {
        return $this->aantalMessages;
    }

    //Function to retrieve messages
    public function findMessages($args)
    {       
        $dbh = $this->db->DBH();

        //$offset for pagination
        $offset = ($args['currentPage'] - 1) * $args['itemsPerPage'];

        $sth = $dbh->prepare("SELECT    SQL_CALC_FOUND_ROWS
                                                    messageen.messageID, 
                                                    messageen.message, 
                                                    messageen.name, 
                                                    messageen.mail
                                            FROM    `messageen` 
                                            ORDER BY messageen.datumToegevoegd DESC 
                                            LIMIT   ?, ?");
        $sth->bindParam(1, $offset, PDO::PARAM_INT);
        $sth->bindParam(2, $args['itemsPerPage'], PDO::PARAM_INT);
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);

        $messages = array();

        while($row = $sth->fetch())
        {
            $message = new message();
            $message->setMessageID(htmlentities(strip_tags($row['messageID'])));
            $message->setSessage(htmlentities(strip_tags($row['message'])));
            $message->setName(htmlentities(strip_tags($row['name'])));
            $message->setMail(htmlentities(strip_tags($row['mail'])));  
            $messages[] = $message; 
        }

        $sth = $dbh->prepare("SELECT FOUND_ROWS() as numberOfMessages");
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);
        $this->numberOfMessages = $sth->fetch();

        return $messages;
    }

    public function setMessageToEdit($args)
    {   
        $sth = $this->db->DBH()->prepare("SELECT    messages.message
                                            FROM    `messages`
                                            WHERE   messages.messageID = ?");
        $sth->bindParam(1, $args['messageID']);
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);
        //return the retrieved message
        while($row = $sth->fetch())
        {
            $message = new message();
            $message->setMessage(htmlentities(strip_tags($row['message'])));
            $message->setMessageID(intval($args['messageID']));
        }

        return $message;
    }

    //functie om messageen aan te passen
    public function save(message $message)
    {   
        //insert part
        //if(isset($message->getname()) && isset($message->getmessage()) && isset($message->getMail()))
        //{
            $sth = $this->db->DBH()->prepare("INSERT INTO   `messages`
                                                    SET     messages.name = ?,
                                                            messages.mail = ?,
                                                            messages.message = ?,
                                                            messages.dateAdded = NOW()");
            $sth->bindParam(1, $message->getName());
            $sth->bindParam(2, $message->getMail());
            $sth->bindParam(3, $message->getMessage());
            $sth->execute();
        //}

        //update part       
        /*if(isset($message->getmessageID()) && isset($message->getmessage()))
        {
            $sth = $this->db->DBH()->prepare("UPDATE    `messageen`
                                                SET     messageen.message = ? 
                                                WHERE   messageen.messageID = ?
                                                LIMIT   1");
            $sth->bindParam(1, $message->getmessage());
            $sth->bindParam(2, $message->getmessageID());
            $sth->execute();
        }*/
    }
}

index.php

<?php
//include file loader.php
include("includes/loader.php");

$guestbook = new guestbook($db);
$user = new user($db);
$messageDAO = new messageDAO($db);

//Make a array named error
$error = array();

//Get action (login/setmessage/editmessage/deletemessage)
if(isset($_GET['action']))
{   
    switch ($_GET['action'])
    {   
        //if login submit is pressed
        case 'login':
            //Check if filled
            if(isset($_POST['username']) && isset($_POST['username']))
            {
                $error['usernameEmpty'] = (bool) !strlen(trim($_POST['username']));
                $error['passwordEmpty'] = (bool) !strlen(trim($_POST['password']));
            }

            if(in_array(1, $error))
            {
                //Assign $error to smarty
                $smarty->assign('error', $error);
            }

            else
            {
                if(isset($_POST['username']) && isset($_POST['username']))
                {
                    $user->setLoggedIn(array('username'=>$_POST['username'],
                    'password'=>$_POST['password']));

                    if($user->getLoggedIn() != true)
                    {                   
                        $smarty->assign('loggedInError', $user->getLoggedIn());
                    }
                }
            }
            break;

        //Als if "place message" is pressed
        case 'placemessage':
            //if user is not logged in
            if($user->getLoggedIn() != true)
            {
                //Controleren of message-velden wel zijn ingevuld
                $error['nameEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags($_POST['messagename']))));
                $error['mailEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags($_POST['messageMail']))));
                $error['messageEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags(str_replace('place message...','', $_POST['messageInput'])))));

                if($error['mailEmpty'] != 1)
                {
                    $error['mailInvalid'] = !filter_input((INPUT_POST), 'messageMail', FILTER_VALIDATE_EMAIL);
                }

                if(in_array(1, $error))
                {
                    $smarty->assign('error', $error);
                }

                else
                {
                    $message = new message();

                    $message->setname($_POST['messagename']);
                    $message->setMail($_POST['messageMail']);
                    $message->setmessage($_POST['messageInput']);

                    dump($message);

                    //place message             
                    $messageDAO->save($message);
                }
            }

            //if user is logged in
            else 
            {
                //is message filled?
                $error['messageEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags(str_replace('place hier uw message...','', $_POST['messageInput'])))));

                if($error['messageEmpty'] != 1)
                {   
                    $user->setUser();

                    $guestbook->placemessage(array('name'=>$user->getLoggedInUsername(), 
                    'mail'=>$user->getLoggedInUserMail(),
                    'messageInput'=>$_POST['messageInput']));
                }

                else 
                {
                    $smarty->assign('error', $error);
                }
            }
            break;

        case 'deletemessage':
            $user->setUser();

            if($user->getLoggedInUserAdmin() == 1)
            {
                if(isset($_GET['messageID']) && is_numeric($_GET['messageID']) && isset($_GET['key']))
                {
                    $guestbook->setURLKey($_GET['messageID']);

                    if($guestbook->getURLKey() == $_GET['key'])
                    {                   
                        $guestbook->verwijdermessage(array('messageID'=>$_GET['messageID']));
                    }
                }
            }
            die(header("location: /index.php"));
            break;
    }
}

if(isset($_GET['pagina']) && is_numeric($_GET['pagina']))
{

    $currentpage = $_GET['pagina'];
}

else
{
    //$currentpage is 1
    $currentpage = 1;
}

$user->setUser();

//assign var to smarty
$smarty->assign('messages', $messageDAO->findmessages(array('currentpage'=>$currentpage, 'itemsPerPagina'=>10)));
$smarty->assign('user', $user);

//Pagination

$numbermessages = $messageDAO->getnumbermessages();


$totalpages = ceil($numbermessages['numbermessages'] / 10);


if($currentpage < 1)
{
    //$currentpage is 1
    $currentpage = 1;
}


if($currentpage > $totalpages)
{

    $currentpage = $totalpages;
}

$smarty->assign('numbermessages', $messageDAO->getnumbermessages());
$smarty->assign('guestbook', $guestbook);
$smarty->assign('currentpage', $currentpage);
$smarty->assign('totalpages', $totalpages);

//display index.tpl
$smarty->display('index.tpl');

Size anlamlı olması için bazı değişkenleri ve işlevleri yeniden adlandırdım (Hollandacadan ingilizceye: P'ye çevirerek) bazen bazı tuhaf durumlarda bulabilirsiniz, çünkü sadece hızlı bir şekilde değiştirdim. Ayrıca bu kodun tamamı değil çünkü kodun 20 dosyası gibi yazmamla sonuçlanır: P


3

Patlama Hapları tarafından belirtildiği gibi, karmaşık bir uygulamada nesnelerin çoğu gerçek dünya varlıklarından (örneğin biniş kartı, fatura veya mp3 dosyası gibi) uygulama bileşenleri (örneğin veritabanı bağlantı havuzları, komutlar, hashpa gibi veri yapıları) ile ilgilidir. ). Tasarım kalıpları üzerine, insanların bu alanda birçok tekrar eden sorunu çözme yollarını gösteren birçok iyi kitap vardır. Bilindiği gibi GOF kitabı kapsamlı fakat çok kuru, Baş İlk Tasarım Desenleri daha erişilebilir olabilir.

Gerçek dünya analiz ve tasarım açısından. İsimler ve fiiller açısından düşünmek genellikle yararlıdır. Örneğin, bir video ödünç verme kütüphanesi (bu eskimiş mi?) Şu şeylere / isimlere sahip olabilir:

  • Video
  • Borçlu

Fiiller açısından:

  • Borçlu, uzun süre video çekebilir
  • Bir Borçlu, mağazaya bir video geri gönderebilir.

Bunlar daha sonra işlemleri olan sınıflara dönüştürülebilir (PHP'yi yaptığımdan bu yana çok zaman geçti, bundan kaçınacağım):

class Borrower
{
  public void borrow(Video video, int daysToBorrow)
  {
     ...
  }

  public void returnVideo(Video video, boolean calculateFine)
  {
     ...
  }
}

Her şey bir sürü pratik ve oyun oynamayı gerektirir. Yapılacak en iyi şey sıkışıp kalmak ve başarısız tasarımlardan ders almaktır. Bence OO, yaşam boyu öğrenmeye ve gelişmeye devam edebileceğiniz bir şeydir (kolay değildir ve hiçbir şeye mükemmel çözümler yoktur). İyi tasarım çoğu zaman yinelemelidir, bu nedenle "Craig's List" web uygulamanız için birkaç farklı fikir denemeyi bekleyin.


1

Yapılacak en iyi şey, uygulamanızın özüne odaklanmanın bir yolunu bulmaktır - "yayın", "kullanıcı", "yayın :: FindByName ()", "kullanıcı-> Validate ()" vb. sıhhi tesisat hakkında çok fazla - gönderileri veritabanı tablolarına yapıştırmak, ekranı farklı aramalar arasında tutarlı bir yazı için tutmak ve "yazılanları girmek" formunu bir veritabanı kaydına yapıştırmak.

Neyse ki, bunu sizin için yapan birçok çerçeve var; OO web uygulamalarındaki baskın paradigma, MVC olarak da bilinen "Model-View-Controller" ; PHP'de, kullanabileceğiniz bir dizi hazır MVC çerçevesi vardır.

Bu, öğrenme ihtiyacınızı arttırırken - artık MVC ve OO hakkında bilgi edinmeniz gerekir - bu, OO çabalarınızın çoğunlukla, iş alanınızı temsil eden "Model" katmanıyla sınırlandırıldığı anlamına gelir; OO'nun en doğal ve etkileyici olduğu yer. MVC çerçevelerinin çoğu, "model" katmanınızı tanımlamanıza olanak tanır ve ardından iskele oluşturma olarak bilinen bir teknik kullanarak otomatik olarak bir web sitesi oluşturabilirsiniz - bu şekilde, etki alanı modeliniz için farklı uygulamalarla deneme yapmanın hızlı bir yolunu elde edersiniz. tüm tesisatını açmak zorunda kaldım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.