tags:

views:

88

answers:

3

Hi there

I'm always coding referencing an object as a single class and if I want to get the collection of that class I just used the Get() and return as a list.

public abstract class Customer
{
   private Int32 customerID;
   private String customerName;

   public abstract List<Customer> Get();
   public abstract bool Add();
   public abstract bool Update();
   public abstract bool Delete();
}

Now ... I've been received comments from other about this that I should create another class for collection to cater this. I've also seen this especially in ORM (Object Relation Mapping) stuff but isn't that too much?

So it will be something like this:

public abstract class CustomerCollection
{    
   public abstract List<Customer> Get();
   public abstract bool Add();
   public abstract bool Update();
   public abstract bool Delete();
}

What is your thought about this?

Thanks

A: 

The method name Get() is ambiguous -- something like Customer.AsList() would make more sense. Or simply just creating a new List containing that Customer when you need one, instead of making a method for it.

Kaleb Brasee
+4  A: 

It sounds like you're asking if it's better to use built-in collections like List<Customer>, or to create your own CustomerList class. Separately from this question, it is important to make sure your single Customer class follows good OO design (and your Get() method seems... strange, at the least).

Setting that aside, my approach is to always use the built-in collection interfaces, not built-in collection classes. For example, any function that returns a collection of Customers should return an IEnumerable<Customer>, ICollection<Customer> or perhaps IList<Customer>, depending on whether you need to be able to just loop through them, count them, or pick ones out in random order, respectively.

Then your initial implementation can just return List<Customer> as you do now, but you can easily replace it with a different collection later if you need more specific functionality.

Updated: If you're really concerned with the idea of extending it later, you could also create an interface:

public interface ICustomerList : IList<Customer> { }

And your default implementation would be just an empty subclass:

public class CustomerList : List<Customer>, ICustomerList { }

And then have all your classes return ICustomerList (you would actually return CustomerList instances). Then in a future version you can extend the ICustomerList interface to add new methods without breaking any code that currently just consumes it like a list.

Note that I haven't tested this approach. YMMV.

Bottom line, though, is that you shouldn't create a new class unless it adds new functionality. Corollary: Always return an interface that exposes the minimum functionality you are willing to support.

Daniel Pryden
Hi Daniel. I like your approach using Interface. Can you give me in detail example based on the class that I have in regards to Interface?
dewacorp.alliances
I've expanded my answer. Does that help? Or were you asking about the .NET generic collections interfaces?
Daniel Pryden
Thanks for that. So I need to to have CustomerList class using ICustomerList then? But then where the methods Get() sits then? I mean how do get all the collection similar like I used to then or do it through Constructor of the CustomerList ?!?!
dewacorp.alliances
Also ... what inside public interface ICustomerList : IList<Customer> { } in this case might be ?!!?
dewacorp.alliances
Answering your second question first: The whole point is that, to start out, you don't need to put anything inside the brackets. Initially, your interface will add nothing that isn't already in the superinterface `IList<Customer>`. However, creating a different interface type will enable you to extend it in the future.
Daniel Pryden
Answering your other question: `CustomerList` extends `List<Customer>` so it should inherit all the constructors from the `List` class. I haven't actually tried this approach before, so YMMV. Alternatively, you could prefer composition over inheritance, and make `CustomerList` just delegate all its methods to an internal `List<Customer>` instance. Either way, you should be able to construct it like you would an ordinary `List`.
Daniel Pryden
Mmmm ... how I am going to get all customers then (querying the database to get all the collection like what I used to be on the Get() method)? Sorry I am bit lost with this concept :)
dewacorp.alliances
If your `Get()` method queries the database to return customer records, then it shouldn't be an instance method of `Customer`. (This is what Pavel Minaev is saying in his comment above.) Either make it a static method, or move it to some kind of factory class. It sounds like what you want is a `Database` class, with a method `GetCustomers()` that returns a `CustomerList` of `Customer`s.
Daniel Pryden
Actually, if you are a bit lost with the concept, I would highly recommend you *don't* use the `ICustomerList` concept I outlined in my answer. Better to just use plain old `IList<Customer>`. For most purposes, you're not going to want to change the public interface of your collection class anyway, so you won't lose anything. And switching to `IList<Customer>` instead of `List<Customer>` enables you to replace the **implementation** of the collection class in the future, which you are much more likely to want to do, especially if you're playing around with ORM solutions.
Daniel Pryden
I agreed that I need to remove this Get() method from Customer class and I am thinking to put under CustomerList at the constructor level to get all customers. But I am very interested in using your approach using interface.
dewacorp.alliances
Do you mean that you want to do `IList<Customer> customers = new CustomerList();` and the constructor would get all customers? While that *could* work, I don't like it, since that's not what I (or most others I think) would expect that code to do. Far better to do something like `IList<Customer> customers = Database.GetCustomers();` which makes it clear where you are getting your customers. Plus, grouping "being a container for data" with "fetching data from database" in a single class smells like a violation of the Single Responsibility Principle.
Daniel Pryden
Yes like this IList<Customer> customers = new CustomerList();. I have specific ORM class for handling the database but different namespace for each object class (the ORM is for Data and the one that I used this here is for Services/Business). Now if I introduce another one called Database ... it's going to a bit messy I guess. I really want to seperate between the Service/Business and Data layer.
dewacorp.alliances
Anyway .. I can put the Get inside the class CustomerList() or Customers() which is more sense.
dewacorp.alliances
What ORM are you using? In every ORM I can think of, you can (and should) refactor getters (especially "get everything" methods) into Factories. If you stubbornly want to do it the wrong way, that's fine -- but don't ask for advice here if you're just going to ignore it anyway. In any case, I think you should read up on Design Patterns, especially the Factory Pattern (http://en.wikipedia.org/wiki/Factory_method_pattern). Also, you should read up on the Single Responsibility Principle, or actually all the SOLID principles: http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
Daniel Pryden
@Daniel: As you can see, I am still learning this sort of concept as quickly as possible. I am trying to fit the design that I have with new stuff.
dewacorp.alliances
+1  A: 

When it comes to using container/collection classes I think it's a matter of personal preferences really. Personally, I like the way you are able to seperate the CRUD methods to a specific container/collection class from the other model classes. It just makes more sense to me not to put such methods on the Customer model class.

bomortensen