Saving an object via a method of its own or via another class?

If I want to save and retrieve an object, should I create another class to handle it, or would it better to do that in the class itself? Or maybe mixing both?

Which is recommended according to OOD paradigm?

For example

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>Class Student
{
public string Name {set; get;}
....
public bool Save()
{
SqlConnection con = ...
// Save the class in the db
}
public bool Retrieve()
{
// search the db for the student and fill the attributes
}
public List<Student> RetrieveAllStudents()
{
// this is such a method I have most problem with it
// that an object returns an array of objects of its own class!
}
}
</code>
<code>Class Student { public string Name {set; get;} .... public bool Save() { SqlConnection con = ... // Save the class in the db } public bool Retrieve() { // search the db for the student and fill the attributes } public List<Student> RetrieveAllStudents() { // this is such a method I have most problem with it // that an object returns an array of objects of its own class! } } </code>
Class Student
{
    public string Name {set; get;}
    ....
    public bool Save()
    {
        SqlConnection con = ...
        // Save the class in the db
    }
    public bool Retrieve()
    {
         // search the db for the student and fill the attributes
    }
    public List<Student> RetrieveAllStudents()
    {
         // this is such a method I have most problem with it 
         // that an object returns an array of objects of its own class!
    }
}

Versus. (I know the following is recommended, however it seems to me a bit against the cohesion of Student class)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>Class Student { /* */ }
Class DB {
public bool AddStudent(Student s)
{
}
public Student RetrieveStudent(Criteria)
{
}
public List<Student> RetrieveAllStudents()
{
}
}
</code>
<code>Class Student { /* */ } Class DB { public bool AddStudent(Student s) { } public Student RetrieveStudent(Criteria) { } public List<Student> RetrieveAllStudents() { } } </code>
Class Student { /* */ }
Class DB {
  public bool AddStudent(Student s)
  {

  }
  public Student RetrieveStudent(Criteria)
  {
  } 
  public List<Student> RetrieveAllStudents()
  {
  }
}

How about mixing them?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> Class Student
{
public string Name {set; get;}
....
public bool Save()
{
/// do some business logic!
db.AddStudent(this);
}
public bool Retrieve()
{
// build the criteria
db.RetrieveStudent(criteria);
// fill the attributes
}
}
</code>
<code> Class Student { public string Name {set; get;} .... public bool Save() { /// do some business logic! db.AddStudent(this); } public bool Retrieve() { // build the criteria db.RetrieveStudent(criteria); // fill the attributes } } </code>
   Class Student
    {
        public string Name {set; get;}
        ....
        public bool Save()
        {
            /// do some business logic!
            db.AddStudent(this);
        }
        public bool Retrieve()
        {
             // build the criteria 
             db.RetrieveStudent(criteria);
             // fill the attributes
        }
    }

3

Single Responsibility Principle, Separation of Concerns and Functional Cohesion. If you read up on these concepts, the answer you get is: Separate them.

A simple reason to separate the Student from the “DB” class (or StudentRepository, to follow more popular conventions) is to allow you to change your “business rules”, present in the Student class, without affecting code that is responsible for persistence, and vice-versa.

This kind of separation is very important, not only between business rules and persistence, but between the many concerns of your system, to allow you to make changes with minimal impact in unrelated modules (minimal because sometimes it is unavoidable). It helps to build more robust systems, that are easier to maintain and are more reliable when there are constant changes.

By having business rules and persistence mixed together, either a single class as in your first example, or with DB as a dependency of Student, you’re coupling two very different concerns. It may look like they belong together; they seem to be cohesive because they use the same data. But here’s the thing: cohesion cannot be measured solely by the data that is shared among procedures, you must also consider the level of abstraction at which they exist. In fact, the ideal type of cohesion is described as:

Functional cohesion is when parts of a module are grouped because they all contribute to a single well-defined task of the module.

And clearly, performing validations about a Student while also persisting it do not form “a single well-defined task”. So again, business rules and persistence mechanisms are two very different aspects of the system, which by many principles of good object oriented design, should be kept separate.

I recommend reading about Clean Architecture, watching this talks about Single Responsibility Principle (where a very similar example is used), and watching this talk about Clean Architecture as well. These concepts outline the reasons behind such separations.

12

Both approaches violate the Single Responsibility Principle. You first version gives the Student class to many responsibilities and ties it to a specific DB access technology. The second leads to a huge DB class which will be responsible not just for students, but for any other kind of data object in your program. EDIT: your third approach is the worst, since it creates a cyclic dependency between the DB class and the Student class.

So if you are not going to write a toy program, use none of them. Instead, use a different class like a StudentRepository for providing an API for loading and saving, assumed you are going to implement the CRUD code on your own. You might also consider to use an ORM framework, which can do the hard work for you (and the framework will typically enforce some decisions where the Load and Save operations have to be placed).

5

There are quite a few patterns that can be used for data persistence. There is the Unit of Work pattern, there is Repository pattern, there are some additional patterns that can be used like the Remote Facade, and so on and on.

Most of those have their fans and their critics. Often it comes to picking what seems to suit the application best and sticking with it (with all its upsides and downsides, i.e. not using both patterns at the same time… unless you’re really sure about that).

As a side note: in your example the RetrieveStudent, AddStudent should be static methods (because they are not instance-dependant).

Another way of having in-class save/load methods is:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class Animal{
public string Name {get; set;}
public void Save(){...}
public static Animal Load(string name){....}
public static string[] GetAllNames(){...} // if you just want to list them
public static Animal[] GetAllAnimals(){...} // if you actually need to retrieve them all
}
</code>
<code>class Animal{ public string Name {get; set;} public void Save(){...} public static Animal Load(string name){....} public static string[] GetAllNames(){...} // if you just want to list them public static Animal[] GetAllAnimals(){...} // if you actually need to retrieve them all } </code>
class Animal{
    public string Name {get; set;}
    public void Save(){...}
    public static Animal Load(string name){....}
    public static string[] GetAllNames(){...} // if you just want to list them
    public static Animal[] GetAllAnimals(){...} // if you actually need to retrieve them all
}

Personally I’d use such approach only in a fairly small applications, possibly tools for personal use or where I can reliably predict that I won’t have a more complicated use cases than just saving or loading objects.

Also personally, see the Unit of Work pattern. When you get to know it, it is really good in both small and large cases. And it is supported by a lot of frameworks/apis, to name EntityFramework or RavenDB for example.

3

If it’s a very simple app where the object is more or less tied to the datastore and visa-versa (i.e. can be thought of as a property of the datastore), then having a .save() method for that class might make sense.

But I think that would be pretty exceptional.

Rather, it’s usually better to let the class manage its data and its functionality (like a good OO citizen), and externalize the persistence mechanism to another class, or set of classes.

The other option is to use a persistence framework that defines persistence declaratively (like with annotations), but that’s still externalizing the persistence.

  • Define a method on that class that serializes the object, and returns a sequence of bytes that you can put in a database or file or whatever
  • Have a constructor for that object that takes such a sequence of bytes as input

About the RetrieveAllStudents() method, your feeling is right, it is indeed probably misplaced, because you might have multiple distinct lists of students. Why not simply keep the list(s) outside of the Student class ?

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật