我在PHP中使用OOP相对较新。它对我的代码的组织和维护有很大的帮助,但我希望能够更好地设计我的类并尽可能高效地使用OOP。我已经阅读了Gang of Four Design Patterns一书,但仍然需要一些帮助。在构建了一些小应用程序后,这是我一直在运行的一件事。
假设我正在构建一个跟踪学校注册信息的应用程序。
我目前采用的方法是在一个学生的记录中创建一个名为student
的类,以及该类中用于CRUD的方法。似乎合乎逻辑的是,我将为此类创建一个以student_id
作为参数的构造函数方法,因此我可以在对象中为所有这些不同的CRUD操作引用它。
但是,随着我继续构建应用程序,我遇到了需要运行返回多个学生的查询的情况。例如,get_all_students_from_grade($grade)
,get_dropdown_of_all_students()
等等。这些方法不仅适用于一个学生,所以我将它们作为student
类中的方法似乎很奇怪因为我在实例化对象时考虑了一个student_id
。显然我可以通过这种方式使它工作,但似乎我做错了。解决这个问题的最佳方式是什么?
答案 0 :(得分:4)
将student
类(属于域类)与其上的操作(业务逻辑或数据访问,根据具体情况)分开,如:
student
- 域对象仅包含数据student_service
或student_dao
(数据访问对象) - 执行操作这有时被认为打破了封装,但它是公认的最佳实践。
Here's有关此事的更多信息。从OOP的观点来看,它提供了比封装破坏更多的缺点。因此,尽管它似乎是一种公认的做法,但它并不是OOP。
答案 1 :(得分:4)
将其分为两类:
您的学生班级对于如何以关系方式存储知之甚少。
$students = student_repository.get_all_students_from_grade($grade)
答案 2 :(得分:1)
我并不假装知道“最好的”方式,但这可能有助于以不同方式解决问题。您可以使类代表应用程序和数据库之间的数据接口,而不是让一个类代表单个学生。
这个类将知道如何从数据库中检索一堆(可能是一个)学生行,将它们缓存在本地数组中,允许应用程序浏览缓存的记录,允许对缓存的记录进行修改,以及何时完成,将缓存的修改写回db(通过生成SQL来考虑更改)。
这样,您可以避免为每次更改触发单个SQL语句(您仍然使用一组行),同时提供对单个对象的访问(通过维护缓存中当前位置的索引) ,并允许应用程序提升此“指针”,因为它调用您的类的方法
答案 3 :(得分:1)
始终有一个起点。在你的情况下,你会从学校,班级等那里得到什么。
$class = new Model_Class;
$students = $class->students;
foreach($students as $student)
{
print $student->name. ' is in class '. $class->name;
}
答案 4 :(得分:1)
我遇到了同样的问题,我猜你在使用MySQL?这是常见的OOP设计挑战之一,因为SQL倾向于压扁所有内容。
我通过以下方式解决了这个问题
1。)创建一个具有三种实例化形式的类,
一个新的
$myStudent = new $Student();
另一个你知道id但需要id数据
的地方$myStudent = new $Student($student_id);
另一个你已经在关联数组中拥有它的数据
$data = array('id'=13,'name' => 'studentname', 'major' => 'compsci');
$myStudent = new $Student($data['id'], $data);
这允许您创建一个可以从mysql运行查询的工厂类,获取数据的关联数组,然后从该数组数据创建student实例,而无需为每个学生实例访问数据库。
这是这样一个类的构造函数:
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);
}
答案 5 :(得分:0)
您可以使用工厂方法,让工厂决定新学生的ID应该是什么。
当然,这家工厂必须阅读一个数据库,看看在哪里开始索引(基于数据库中有多少学生),你必须决定如何处理被删除的学生(如果这是一个可能性)。
至于你描述的方法,我不明白为什么你必须把它们包括在你的学生班里。你可以但它应该是静态方法而不是成员方法。
答案 6 :(得分:0)
就像尼尔在评论中所说的那样(不确定为什么我们没有给出答案),你也应该有Course
和School
类。您可以在School
和课程特定方法(所有具有一定年级的课程中的所有学生等)中使用针对学校的方法(让所有学生达到给定年级,缺少给定天数等)在Course
班。
你认为在标准CRUD中你不想给代表个人的类(即Student
类)加载自身的倍数是正确的。 另一方面,如果您想要更多ActiveRecord样式的数据加载(这是Ruby on Rails使用的),那么 实际上在Student
类本身上创建所有Student
加载器方法静态方法。这取决于你想要如何设计它,这在一定程度上取决于你的数据模型将变得多么复杂。
答案 7 :(得分:-1)
你应该在学生身上制作class methods。