views:

45

answers:

3

I have a product class which contains 11 public fields.

ProductId
ShortTitle
LongTitle
Description
Price
Length
Width
Depth
Material
Img
Colors
Pattern

The number of fields may grow with attributes for more specific product tyes. The description may contain a large amount of data.

I want to create a slim version of this product class that only contains the data needed. I'm only displaying 4 of the 12 fields when listing products on a category page. It seems like a waste to retrieve all of the data when most of it isn't being used.

I created a parent class of ProductListing that contains the 4 fields I need for the category page

ProductId
ShortTitle
Price
Img

Then created a class of Product that inherits from ProductListing containing all product data. It seems backwards as "ProductListing" is not a kind of "Product" but I just started reading about inheritance a few months ago so it's stil a little new to me.

Is there a better way to get a slim object so I'm not pulling data I don't need? Is the solution I have in place fine how it is?

+1  A: 

I personally do not favor inheritance for these kinds of problems because it can become confusing over time. Specifically, I try to avoid having two concrete classes in my inheritance hierarchy where one inherits from the other and both can be instantiated and used.

How about creating a ProductCoreDetail class that has the essential fields you need and aggregating it inside of the Product class. You can still expose the public fields by declaring them as public fields and proxying them to the nested ProductCoreDetail instance.

The benefit of this model is that any shared implementation code can be placed in ProductCoreDetail. Also, you can choose to define an additional interface IProductCoreDetail that both Product and ProductCoreDetail implement so that you can pass either instance to methods that just care about code information. I would also never exposed the aggregate instance publicly to consumer of Product.

Here's a code example:

// interface that allows functional polymorphism
public interface IProductCoreDetail
{
    public int ProductId { get; set; }
    public string ShortTitle { get; set; }
    public decimal Price { get; set; }
    public string Img { get; set; }
}

// class used for lightweight operations
public class ProductCoreDetail : IProductCoreDetail
{
    // these would be implemented here..
    public int ProductId { get; set; }
    public string ShortTitle { get; set; }
    public decimal Price { get; set; }
    public string Img { get; set; }

    // any additional methods needed...
}

public class Product : IProductCoreDetail
{
    private readonly ProductCoreDetail m_CoreDetail;

    public int ProductId    { get { return m_CoreDetail.ProductId; } }
    public string ShortTitle { get { return m_CoreDetail.ShortTitle; } }
    public decimal Price { get { return m_CoreDetail.Price; } }
    public string Img { get { return m_CoreDetail.Img; } }

    // other fields...
    public string LongTitle
    public string Description
    public int Length
    public int Width
    public int Depth
    public int Material
    public int Colors
    public int Pattern
}
LBushkin
A: 

I agree with LBushkin that inheritence is the wrong approach here. Inheritence suggests that TypeB is a TypeA. In your case, the relationship is not quite the same. I used to create classes that were subsets of a large entity for things like search results, list box items, etc. But now with C# 3.5's anonymous type support and LINQ projections, I rarely need to do that anymore.

// C#
var results = from p in products
              select new {
                  p.ProductId,
                  p.ShortTitle,
                  p.Price,
                  p.Img };

// VB.NET
Dim results = From p in products _
              Select p.ProductId, p.ShortTitle, p.Price, p.Img

This creates an unnamed type "on-the-fly" that contains only the fields you specified. It is immutable so the fields cannot be changed via this "mini" class but it supports equality and comparison.

But when I do need to create a named type, I typically just create a separate class that has no relationship to the main class other than a lazy-loaded reference to the "full" version of the object.

Josh Einstein
A: 

I wouldn't use a separate class or inheritance.

For your slim version, why not just retrieve only the data you need, and leave the other fields empty? You might have two queries: one that fills all the fields, and another that only fills the slim fields. If you need to differentiate between the two, that's easy if one of the non-slim fields is NOT NULL in your DB; just check for null in the object.

RickNZ