2010-01-01 108 views
6

我在PHP中使用OOP比较新。这对我的代码的组织和维护非常有帮助,但我希望在设计我的类和尽可能高效地使用OOP方面做得更好。我读过四本纲要设计模式书,但仍需要一些帮助。在构建一些小应用程序之后,我继续运行一件事。OOP设计问题

假设我正在构建一个跟踪学校注册信息的应用程序。

我目前处理这个问题的方法是在一个单独的学生记录中创建一个名为student的类,以及该类中针对CRUD的方法。看起来合乎逻辑的是,我将这个类的构造方法以student_id作为参数,所以我可以从对象中为所有这些不同的CRUD操作引用它。

但是,当我继续构建应用程序时,我遇到了需要运行返回多个学生的查询的情况。例如,get_all_students_from_grade($grade),10等等。这些方法并不适用于一个学生,所以看起来很奇怪,我会把它们作为我的student类中的方法,因为我想到了一个student_id实例化对象。很明显,我可以通过这种方式来实现这一目标,但看起来我“做错了”。解决这个问题的最好方法是什么?

+2

如果你有“学生”,你可能也想“当然”和“学校”,这似乎是“get_students”方法好位置。 – 2010-01-01 18:28:32

回答

4

分离student类(这是一个域类)从操作上它(业务逻辑或数据访问,根据情况),如:

  • student - 域对象只包含数据
  • student_servicestudent_dao(数据访问对象) - 执行操作

这有时认为是破坏封装,但它是一个公认的最佳PRAC蒂斯。

Here's有关此事的更多信息。从OOP的观点来看,它比封装的破裂提供了更多的缺点。所以即使它看起来是一种公认​​的做法,它也不是OOP。

+0

这听起来像是最简单的方法。你能描述/提供描述“域”类/对象概念的链接吗?我无法用Google快速找到任何内容。 – Matthew 2010-01-01 18:43:54

+0

@Matthew:在Martin Fowler的书(应用UML和模式)中有很好的描述,但你可以在这里有一个想法: http://martinfowler.com/eaaCatalog/domainModel.html 和这里 http:// en。 wikipedia.org/wiki/Domain_model – 2010-01-01 18:57:47

+0

@Matthew:如果你想为SQL表提供面向对象的接口,那么我建议使用类似Active Records等的东西。控制器类可以使用这些对象进行CRUD操作(它们也支持手动SQL查询)。 你的想法是正确的。我只是认为你不应该再次发明轮子,但对于所有非数据库操作,你应该使用@Bozho正在讨论的方法。另一方面,来自我的问题很快;为什么人们不会使用更多的控制器类的静态类方法? – 2010-01-01 19:55:04

-1

你应该让他们在学生class methods

+0

我不明白这一个downvotes。 – 2010-03-29 05:38:43

4

打破它分为两类:

  1. 学生
  2. student_repository

您的学生类并不知道它是如何关联存储。

$students = student_repository.get_all_students_from_grade($grade) 
0

您可以使用工厂方法,让工厂决定新学生的ID应该是什么。

当然,这家工厂必须读取数据库才能看到索引的起始位置(根据数据库中有多少学生),并且您必须决定如何处理已删除的学生(如果这是一个潜在可能)。

至于你所描述的方法,我不明白为什么你必须包括在你的学生班。你可以但它应该是一个静态方法,而不是一个成员方法。

1

我不假装知道“最好”的方式,但它可能有助于以不同的方式解决问题。不要让一个类代表一个学生,你可以让这个类代表你的应用程序和数据库之间的数据接口。

这个类将知道如何从数据库中检索一堆(可能是一个)学生行,将它们缓存在本地数组中,允许应用程序浏览缓存记录,允许修改缓存记录,以及何时完成后,将缓存的修改写回数据库(通过生成SQL来说明更改)。

这样,您可以避免为每个更改启动单个SQL状态(您仍然使用一组行),并且同时提供对各个对象的访问权限(通过维护指向当前位置的索引缓存,并允许这个“指针”由应用程序进阶,因为它调用你的类的方法)

0

像尼尔在他的评论中说的(不知道为什么我们没有答案),你应该可能也有CourseSchool类。您可以在Course班级中使用School以及特定课程方法(具有某一年级的课程中的所有学生等),针对特定学校的方法(让所有学生处于特定等级,缺勤天数等) 。

你认为在标准CRUD中你不想给一个代表个人的班级(即Student班级)加载其自身倍数的责任是正确的。 在另一方面,如果你要更多的ActiveRecord风格数据加载(这是Ruby on Rails的员工),那么你实际上使所有Student加载器方法上Student类本身的静态方法。这取决于你想如何设计它,这部分取决于你的数据模型将变得多么复杂。

1

总是有一个起点。就你而言,这将是你从学生(如学校,班级等)获得什么。

$class = new Model_Class; 

$students = $class->students; 

foreach($students as $student) 
{ 
    print $student->name. ' is in class '. $class->name; 
} 
1

我来过这个相同的问题,我猜你正在使用MySQL吗?这是常见的面向对象设计挑战之一,因为SQL倾向于将所有东西都弄平。

我这样做解决了这个以下

1)作出有三种形式实例化一个类,

之一,它是新的

$myStudent = new $Student(); 

另一个地方,你知道的ID但需要ID数据

$myStudent = new $Student($student_id); 

和另一个你已经有它的dat一个关联数组

$data = array('id'=13,'name' => 'studentname', 'major' => 'compsci'); 
$myStudent = new $Student($data['id'], $data); 

这可以让你做,可以从MySQL运行查询一个工厂类,获取数据的关联数组,然后创建数组数据学生的情况下,没有击中数据库每个学生的实例。

这里是这样一类的构造函数:

public function __construct($id=FALSE, $data=FALSE) 
{ 
    if(!$id) $this->is_new = true; 
    else if($id && !$data) $this->get_data_from_db($id); 
    else if($id && $data) $this->set_data($data); 

} 
+0

这是一个有趣的方法,但如果你总是知道该期待什么,那么与班级一起工作会不会更容易?如果我在代码中看到对象,我就无法分辨出它是什么样的学生对象,而没有找到实例化的那一行。 – Matthew 2010-01-01 18:53:47

+0

我不确定我是否理解你的问题,在上面的例子中他们都是一样的,哦,我忘了显示可选的参数,我会添加到我的解释。 – 2010-01-01 18:58:16

+0

我明白你现在在说什么。但是在所有三个例子中,这个班级都是作为一名学生实例化的,而我遇到的问题是将一名学生的CRUD活动与涉及多名学生的方法区分开来。 – Matthew 2010-01-01 19:02:29