我正在使用面向过程编程还是面向对象编程(OOP)?

3
基本上,我正在从过程式编码转向面向对象编程。我正在尝试实现面向对象编程的原则,但我有一个困扰的感觉,即实际上我只是用对象编写过程式风格。
比如说,我有一个管道/椅子/打印机等列表,它们都被列为我的单个表数据库中的产品。我需要构建一个Web应用程序,显示整个列表和根据其类型显示项目,重点是正确使用面向对象编程及其范例。
只是这样做有什么问题吗?
     CLass Show
     {

      public function showALL(){
      $prep = "SELECT * FROM myProducts";
      $q = $this->db-> prepare($prep);     
      $q->execute();
      while ($row = $q->fetch()) 
          {
            echo "bla bla bla some arranged display".$row['something']       
          }
      }
然后只需要简单地执行以下步骤。
$sth = new show();
$sth->showAll();

我会实现更加具体的显示方法,例如:
showSpecificProduct($id)->(用户单击链接时,$id将通过$_GET传递,我们将有一个独立的product.php文件,其中基本上只包含)
include('show.class.php');
$sth = new show();
$sth->showSpecificProduct($id);

showSpecificProduct() 会执行查询和输出 HTML 显示的操作。

总之,我现在这样做是正确的还是只是用类和对象进行过程式编码。如果我做错了,有什么解决方法或提示吗?


1
一个好的开始是从单一职责原则的角度开始思考:http://en.wikipedia.org/wiki/Single_responsibility_principle(“为显示格式化HTML”可以被视为一项职责) - laher
我认为这是一个非常好的问题。大多数人一开始很难理解面向对象编程,但确实值得努力。提出问题将使您远离从一开始就形成的不良习惯和做法。 - adlawson
谢谢大家,你们消除了我心中的一些疑虑,并指引我朝着正确的方向前进。我还有很多要阅读和学习。 :) - Matija Milković
5个回答

2
更好的选择是实现一个仓储模式。一个示例接口可能是:
interface ProductRepository
{
    public function find($id);

    public function fetchAll();
}

你将会创建一个该接口的具体实现。
class DbProductRepository implements ProductRepsoitory
{
    private $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function find($id)
    {
        // prepare execute SQL statement
        // Fetch result
        // return result
    }

    public function fetchAll()
    {
        // etc
    }
}

通常直接从方法或函数中使用echo是个不好的主意。应该让方法返回适当的对象/数组/等等,然后使用这些结果。

2
除了@Phil和@Drew描述的模型实践之外,我建议您将业务、数据和视图层分开。
我已经提供了一个非常简单的版本,需要在您的实现中进行扩展,但是这个想法是将您的数据库查询与输出分开,并在控制器中将两者几乎“连接”在一起。
class ProductController
{
    public $view;

    public function __construct() {
        $this->view = new View;
    }

    public function indexAction() {
        $model = new DbProductRepository;
        $products = $model->fetchAll();

        $this->view->products = $products;
        $this->view->render('index', 'product');
    }
}

class View
{
    protected $_variables = array();        

    public function __get($name) {
        return isset($this->_variables['get']) ? $this->_variables['get'] : null;
    }

    public function __set($name, $value) {
        $this->_variables[$name] = $value;
    }

    public function render($action, $controller) {
        require_once '/path/to/views/' . $controller . '/' . $action . '.php';
    }
}

// in /path/to/views/product/index.php
foreach ($this->products as $product) {
    echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}

1

你所描述的情况似乎是MVC的一个很好的候选者。

在你的情况下,我会创建一个专门用于访问数据(执行产品类别或特定产品的选择)的类,然后有一个不同的文件(你的视图)接受输出并显示它。

它可能看起来像这样:

class Product_Model {
    public function find($prodId) { ... }
    public function fetchAll($category = '') { ... }
    public function search($string) { ... }
}

然后在其他地方你可以这样做:

$products = new Product_Model();
$list = $products->fetchAll(37); // get all from category 37

// in true MVC, you would have a view that you would assign the list to
// $view->list = $list;

foreach($ilst as $product) {
    echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}

MVC的基本原则是,您有模型类,它们只是表示来自某些数据源(例如数据库)的数据的对象。您可能会有一个映射器,将数据库中的数据映射到和从您的数据对象中。然后控制器将从您的模型类获取数据,并将信息发送到视图,在那里处理实际的呈现。在控制器中具有视图逻辑(HTML / JavaScript)是不可取的,直接从控制器与您的数据交互也是如此。

1
首先,您需要了解类自动加载。这样,您就不必包含您使用的每个类,只需使用它,自动加载程序将为您找到正确的文件进行包含。

http://php.net/manual/en/language.oop5.autoload.php

每个类都应该有一个单一的职责。你不会有一个连接到数据库并更改某些用户数据的单一类。相反,你会有一个数据库类,你会将其传递给用户类,用户类将使用数据库类来访问数据库。每个函数也应该有一个单一的职责。你永远不应该在函数名中加入“and”。
你不希望一个对象知道另一个对象的属性。这会导致在一个类中进行更改强制你在另一个类中进行更改,最终变得难以进行更改。属性应该供对象内部使用。
在编写类之前,你应该首先考虑如何使用它(参见测试驱动开发)。在使用时,你希望代码看起来是什么样子?
$user = new User($db_object);
$user->load($id);
$user->setName($new_name);
$user->save();

现在您知道了想要如何使用它,编写正确的代码就更容易了。

有机会时,请研究敏捷原则。


0

一个经验法则是类名通常应该是名词,因为面向对象编程是关于拥有与真实概念对象相对应的软件对象。类成员函数通常是动词,也就是你可以对一个对象执行的操作。

在你的例子中,show 是一个奇怪的类名。更典型的做法是使用一个名为 ProductViewer 的类,并具有一个名为 show() 或 list() 的成员函数。此外,您还可以使用子类作为一种获取特定产品类型的自定义视图等专业功能的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接