草庐IT

php - 组织类(class) - 帮助 OOP 初学者

coder 2024-04-25 原文

我读到的关于类结构的示例通常从一个基类开始,然后该基类通过更细化的类进行扩展,即。经常被引用的:

class Animal {}
class Rodent extends Animal {}
class Mouse extends Rodent {}

但在我的 CMS/电子商务系统的现实世界项目中,我似乎正在以相反的方式构建这种结构,即从一种情况的类开始,然后用与整个项目相关但实际上与整个项目相关的东西扩展它扩展类。

class page {}
class product extends page{}
class category extends product{}
class basket extends category{}
class shop extends basket{}

因此,通过这种方式,我只需调用 $s = new shop() 并访问运行该商店所需的所有类/方法。我想我只是扩展类以保存分别实例化每个类。这似乎与我读过的大多数示例背道而驰,而且我肯定错过了 OOP 在这里的全部内容。随着类(class)的扩展,我的类(class)似乎变得越来越普遍,越来越不专业。

我应该继续这种方式还是重新构建我构建这个类系统的方式?

最佳答案

您可以在谷歌上搜索组合优于继承is-a vs has-a

在您的设计草图中,您混合了一堆您注意到的东西。最容易剖析的示例是 class category{} extends product。一个类别不是产品,但它有/包含多种产品。这会更合适:

class product {
        public $title; // for simplicity
        public $price; // for simplicity
}
class category {
        private $name;
        private $products;
        public function __construct($name) {
                $this->name = $name;
                $this->products = array();
        }   
        public function addProduct(product $p) {
                $this->products[] = $p; 
        }   
        public function printProducts() {
                $product_names = array_map(function($product) {
                        return $product->title;
                }, $this->products);
                echo implode(', ', $product_names);
        }   
}

$c = new category('fruits');
$apple = new product;
$apple->title = 'apple';
$orange = new product;
$orange->title = 'orange';
$banana = new product;
$banana->title = 'banana';

$c->addProduct($apple);
$c->addProduct($orange);
$c->addProduct($banana);

$c->printProducts();

注意如何将两个实体分开并让 product 担心产品是什么以及可以做什么,以及类别是什么(名称)、有(产品)和可以做什么(打印列表其产品)。

解耦(最小化类之间的依赖性)的另一个技巧是,您应该尽可能长时间地让数据远离您的对象。上面示例中的类很简单但很实用。如果您可以使它们在没有数据库访问权限的情况下工作(这是拥有大量 extends 链的常见原因),您就会意识到这些类都不需要数据库访问权限,而是可以填充/创建它们通过有权访问数据库的类。像这样:

class category_factory {
  public function __construct(PDO $pdo) { $this->pdo = $pdo; }
  public function getCategories() {
    $rows = $this->pdo->query("SELECT * FROM categories")->fetchAll();
    $categories = array();
    foreach($rows as $row) {
      $categories[] = new category($row['name']);
    }
    return $categories;
  }
}

* PDO包含数据库连接

关于php - 组织类(class) - 帮助 OOP 初学者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7481870/

有关php - 组织类(class) - 帮助 OOP 初学者的更多相关文章

  1. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  2. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  3. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  4. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  5. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  6. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  7. ruby - 帮助使用 Ruby 中的 "Whenever"gem 来执行 cron 任务 - 2

    我以前没有使用过cron,所以我不能确定我这样做是对的。我想要自动化的任务似乎没有运行。我在终端中执行了这些步骤:sudogeminstall每当切换到应用程序目录无论何时。(这创建了文件schedule.rb)我将此代码添加到schedule.rb:every10.minutesdorunner"User.vote",environment=>"development"endevery:hourdorunner"Digest.rss",:environment=>"development"end我将此代码添加到deploy.rb:after"deploy:symlink","depl

  8. ruby - 使用 Class.new 时访问外部范围 - 2

    是否有可能以某种方式访问​​Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(

  9. Ruby 最佳实践 : working with classes - 2

    参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin

  10. ruby - 模块中的 instance_eval 与 class_eval - 2

    classFooincludeModule.new{class_eval"deflab;puts'm'end"}deflabsuperputs'c'endendFoo.new.lab#=>mc======================================================================classFooincludeModule.new{instance_eval"deflab;puts'm'end"}deflabsuperputs'c'endend注意这里我把class_eval改成了instance_evalFoo.new.labresc

随机推荐