473,413 Members | 1,727 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,413 software developers and data experts.

Proper design of classes

Hi,

I have a couple of questions about the proper design of classes.
I'll use a simple Customer class for my question.

1) Lets say that I have this Customer class like I said, and I want to
distinguish
between different types of customers, for example private, business,
other etc.
This will allow me to filter customers based on their type. Should I
derive from
a base class Customer or should I make it a property of the class,
perhaps an
Enum with the relevant options.
2) I might also have different, let's say "schemes", for the name of the
customer,
so if it's a private customer, the class would have a PrivateName and
LastName
properties, and if it's a business customer, it would have a CompanyName
property. This might be possible I think with the derivation option,
where the
base class Customer has no property realting to the its name, and is
added by
each derived Customer class, for example PrivateCustomer adds PrivateName
and LastName, and BusinessCustomer adds CompanyName (although I'm not
sure that this is good design in term of good OO practice, where classes
should be derived if they have different behaviour, not data).

I've once seen a financial software where it differentiated between
customers by
taking the property approach, and it had the properties LastNameCompanyName
(yes, it's used for either last name or company name) and FirstName, which
is not
used in case of a business customer. I don't like this approach because in
every
document, for example Invoice, you'd see fields like
"Company/Last Name: _________", which I don't like.

I would greatly appreciate any help here.
Ben
Jul 23 '08 #1
8 1615
Ben wrote:
Hi,

I have a couple of questions about the proper design of classes.
I'll use a simple Customer class for my question.

1) Lets say that I have this Customer class like I said, and I want to
distinguish
between different types of customers, for example private, business,
other etc.
This will allow me to filter customers based on their type. Should I
derive from
a base class Customer or should I make it a property of the class,
perhaps an
Enum with the relevant options.
That mainly depends on the data that you need to store for each type. If
the business customer needs to contain some data that would not make
sense for a private customer (or vice versa), they should be different
classes.
2) I might also have different, let's say "schemes", for the name of the
customer,
so if it's a private customer, the class would have a PrivateName and
LastName
properties, and if it's a business customer, it would have a CompanyName
property. This might be possible I think with the derivation option,
where the
base class Customer has no property realting to the its name, and is
added by
each derived Customer class, for example PrivateCustomer adds PrivateName
and LastName, and BusinessCustomer adds CompanyName (although I'm not
sure that this is good design in term of good OO practice, where classes
should be derived if they have different behaviour, not data).
Well, a class could have slightly different behaviour, as long as the
properties and methods are the same. For example, depedning on the value
of an enum, the Name property could either return CompanyName or
FirstName + " " + LastName. (Whether all three values should be in the
same class is a different question - it's just an example.)
I've once seen a financial software where it differentiated between
customers by
taking the property approach, and it had the properties LastNameCompanyName
(yes, it's used for either last name or company name) and FirstName, which
is not
used in case of a business customer. I don't like this approach because in
every
document, for example Invoice, you'd see fields like
"Company/Last Name: _________", which I don't like.
That could, and should, be avoided regardless of how you choose to solve
it. A property should not have different meanings, or be used/unused,
depending on some other property. And even if it did, it should
definitely not be visible in the user interface...

--
Göran Andersson
_____
http://www.guffa.com
Jul 23 '08 #2
Hiya,
what you might end up having is a class explosion. I will suggest you
use interface that inherits from other interfaces. Like you can have
IPrivateCustomer, IBusinessCustomer, ICustomer. Your ICustomer Inherits from
the IPrivateCustomer and IBusinessCustomer.

So you will have an implementation class called customer which implements
ICustomer, since your ICustomer interface inherits from different interfaces,
you will explitcitly implement the other interfaces as well. So you can
dynamically at runtime cast your Customer class to those different
interface(s) when you need their certain properties, method or functionality.
For example:

public interface IPrivateCustomer
{
string PrivateName { get; set; }
string PrivateAddress { get; set; }
}

public interface IBusinessCustomer
{
string CompanyName { get; set; }
}

public interface ICustomer : IPrivateCustomer, IBusinessCustomer
{
string FirstName { get; set; }
string LastName { get; set; }
}

public class Customer : ICustomer
{
//Explicity implements all methods/properties of the three interfaces.
}


Create an instance of the Customer Class here by doing the any or all of
following :
Customer customer = new Customer();

IPrivateCustomer privateCustomer = customer as IPrivateCustomer;
IBusinessCustomer businessCustomer = customer as IBusinessCustomer;
ICustomer iCustomer = customer as ICustomer;

The flexibility that you gain from this approach is that you only have a
single customer class and you can add new interface and remove others.

Also you may want to look at the Factory pattern, which will support the
creation of an object based on the type you supplied. You can use the
combination of the factory pattern with the simple scenario that i ahve given.

I hope this work.

Cheers and Enjoy.
Jul 23 '08 #3
Ben wrote:
I have a couple of questions about the proper design of classes.
I'll use a simple Customer class for my question.

1) Lets say that I have this Customer class like I said, and I want to
distinguish
between different types of customers, for example private, business,
other etc.
This will allow me to filter customers based on their type. Should I
derive from
a base class Customer or should I make it a property of the class,
perhaps an
Enum with the relevant options.
2) I might also have different, let's say "schemes", for the name of the
customer,
so if it's a private customer, the class would have a PrivateName and
LastName
properties, and if it's a business customer, it would have a CompanyName
property. This might be possible I think with the derivation option,
where the
base class Customer has no property realting to the its name, and is
added by
each derived Customer class, for example PrivateCustomer adds PrivateName
and LastName, and BusinessCustomer adds CompanyName (although I'm not
sure that this is good design in term of good OO practice, where classes
should be derived if they have different behaviour, not data).

I've once seen a financial software where it differentiated between
customers by
taking the property approach, and it had the properties LastNameCompanyName
(yes, it's used for either last name or company name) and FirstName, which
is not
used in case of a business customer. I don't like this approach because in
every
document, for example Invoice, you'd see fields like
"Company/Last Name: _________", which I don't like.

I would greatly appreciate any help here.
As described, a class-per-type approach seems to be the best here,
since different types of customers actually do have different
properties for you. If you ever need to display them all together, you
might have to introduce some kind of a DisplayName property that would
be the "most appropriate" name for a given customer type.
Jul 23 '08 #4


"Pavel Minaev"
Interface is more polymorphic than having large libraries of class(es). I
will suggest you look into what gains an interface can give to you.
Jul 23 '08 #5
Ben wrote:
I have a couple of questions about the proper design of classes.
I'll use a simple Customer class for my question.

1) Lets say that I have this Customer class like I said, and I want to
distinguish
between different types of customers, for example private, business,
other etc.
This will allow me to filter customers based on their type. Should I
derive from
a base class Customer or should I make it a property of the class,
perhaps an
Enum with the relevant options.
2) I might also have different, let's say "schemes", for the name of the
customer,
so if it's a private customer, the class would have a PrivateName and
LastName
properties, and if it's a business customer, it would have a CompanyName
property. This might be possible I think with the derivation option,
where the
base class Customer has no property realting to the its name, and is
added by
each derived Customer class, for example PrivateCustomer adds PrivateName
and LastName, and BusinessCustomer adds CompanyName (although I'm not
sure that this is good design in term of good OO practice, where classes
should be derived if they have different behaviour, not data).

I've once seen a financial software where it differentiated between
customers by
taking the property approach, and it had the properties LastNameCompanyName
(yes, it's used for either last name or company name) and FirstName, which
is not
used in case of a business customer. I don't like this approach because in
every
document, for example Invoice, you'd see fields like
"Company/Last Name: _________", which I don't like.
abstract base class and concrete sub classes would be my recommendation
for this case.

Arne
Jul 24 '08 #6
Ahmed Salako wrote:
what you might end up having is a class explosion.
Is interface explosion better ?

:-)
I will suggest you
use interface that inherits from other interfaces. Like you can have
IPrivateCustomer, IBusinessCustomer, ICustomer. Your ICustomer Inherits from
the IPrivateCustomer and IBusinessCustomer.

So you will have an implementation class called customer which implements
ICustomer, since your ICustomer interface inherits from different interfaces,
you will explitcitly implement the other interfaces as well. So you can
dynamically at runtime cast your Customer class to those different
interface(s) when you need their certain properties, method or functionality.
For example:

public interface IPrivateCustomer
{
string PrivateName { get; set; }
string PrivateAddress { get; set; }
}

public interface IBusinessCustomer
{
string CompanyName { get; set; }
}

public interface ICustomer : IPrivateCustomer, IBusinessCustomer
{
string FirstName { get; set; }
string LastName { get; set; }
}

public class Customer : ICustomer
{
//Explicity implements all methods/properties of the three interfaces.
}

Create an instance of the Customer Class here by doing the any or all of
following :

Customer customer = new Customer();

IPrivateCustomer privateCustomer = customer as IPrivateCustomer;
IBusinessCustomer businessCustomer = customer as IBusinessCustomer;
ICustomer iCustomer = customer as ICustomer;

The flexibility that you gain from this approach is that you only have a
single customer class and you can add new interface and remove others.
Or he could just drop all the interfaces since they do not provide
and value for him. They don't help solve the problems he mention.

Arne
Jul 24 '08 #7
what you might end up having is a class explosion. I will suggest
you
use interface that inherits from other interfaces. Like you can have
IPrivateCustomer, IBusinessCustomer, ICustomer. Your ICustomer Inherits
from
the IPrivateCustomer and IBusinessCustomer.
I disagree with this. Surely you're just replacing "class explosion" with
"interface explosion" and without a business case for introducing interfaces
at all. Interfaces are very powerful as we know for a lot of scenarios, but
it hasn't been asked for here. All that's important is modelling the
business domain appropriately in such a way as it can be programmed against.

now back to the OP
1) Lets say that I have this Customer class like I said, and I want to
distinguish between different types of customers, for example private,
business,
other etc. This will allow me to filter customers based on their type.
Should I
derive from a base class Customer or should I make it a property of the
class,
perhaps an Enum with the relevant options.
There are of course lots of approaches and possible answers, all of which
depend on what you're trying to achieve rather than there being any *right*
way of designing it. Sure, you could go for a property on the Customer
describing its type. It's easy and effective. I've done things like this
before quite successfully, however that's in relatively simple applications.
One thing I would say if you go this way is don't use an enum. An enum won't
leave you any room for adding new Customer types without recompilation of
the full application - and even when you do that it's entirely possible that
the new enum value will cause client code to silently fail by not
recognising the new customer type. Far better to have a CustomerType class
(perhaps even loaded from your DB)

In more general terms, personally, I'd be more inclined to store common data
in a base Customer class, and move the functionality to subclasses or
external code where possible.

Very often people put every last bit of functionality in a single object,
and I think this is bad design. You could use the customer instance to
obtain extended information, or put specific data in an associated set of
CustomerInfo classes.. This is a bit like the interface approach offered
earlier, but it doesn't require you to implement each interface in your
customer class. For example

class CustomerInfo;
class CompanyInfo;
class ProspectInfo;
class IntranetUserCustomerInfo

Customer customer = LoadCustomer("cust-id");
ProspectInfo prospect = PropsectInfo.LoadFor(customer);
if( prospect.LikelihoodOfClosure < 0.5 ) { SendMarketingInfo(prospect); }

etc..

I prefer the functionality-driven approach. So you have your base customer
data, in a base class which is good enough for a lot of scenarios. but then
you instantiate specific Customer subclasses depending on the context, each
that imply differnt behaviour. However - and this is the key thing - any of
them can be instatiated against the same set of customer data (eg a database
record ID). Loading the core customer data can be then done either by the
base class alone, or by any subclass (and hence the base class too), and any
other behaviour can be handled by the subclass - if used.

So this example describes a task-based hierarchy which provides a base
customer that does all the common stuff, loading name, email address etc,
but it allows implementation of a task list for any number of contextual
subclasses... and this can be extended by third party code .. whatever.

// this is the base class. All Customers in the task based system,
regardless of the context can be treated as Customers.
public class Customer
{
// this method will call LoadSpecificData()
// which does nothing here, but it can be overridden by
// subclasses to obtain any further info required
public void Load(int recordID)
{
Data data = GetDataFromDB(recordID); // DataSet, XmlNode etc
AssignCommonCustomerDataToFields(data, recordID);
LoadSpecificData(data);
}

// override in subclasses to load context specific data.
// The same model can, and should be used for saving records too.
protected virtual void LoadSpecificData(Data data, int recordID)
{
// NOOP
}
}

// this subclass defines a new method that must be implemented.
// The WorkItem class is implied, and expected to be subclassed too.
public abstract class TaskBasedCustomer : Customer
{
// example specialisation
public abstract IEnumerable<WorkItemGetWorkItems();
{ yield break; }
}

// this describes the email communication context of the customer
public class CommunicatingCustomer : TaskBasedCustomer
{
// .. specific properties..

// from Customer
override void LoadSpecificData(Data data, int recordID)
{
LoadContactInformation(data);
}

// from TaskBasedCustomer
override IEnumerable<WorkItemGetWorkItems()
{
foreach(Email received in GetInbox())
{
yield return new EmailReceivedWorkItem(received);
}
}
}

// this describes the helpdesk/support context of the customer
public class HelpdeskCustomer : TaskBasedCustomer
{
// .. specific properties..

// from Customer
override LoadSpecificData(Data data, int recordID)
{
LoadIncidentHistoryFromCRM(recordID);
}

// from TaskBasedCustomer
override IEnumerable<WorkItemGetWorkItems()
{
foreach(Incident logged in IncidentHistory)
{
if(logged.Status == IncidentStatus.Open)
{
yield return new OpenIncidentWorkItem(logged);
}
}
}
}
now what does this give you... well, in this example, you could have a
master list of customers; with customer ids, and this could generate a link
to an Inbox page like inbox?id=[customerId]. and that page's codebehind
looks like this

TaskBasedCustomer customer = new CommunicatingCustomer();
customer.Load(Request["customerId"])
InboxDataGrid.DataSource = customer.GetWorkItems();
InboxDataGrid.DataBind();

or you could have a helpdesk info page listing the customers incidents that
works like this:

TaskBasedCustomer customer = new HelpdeskCustomer();
customer.Load(Request["customerId"])
IncidentDataGrid.DataSource = customer.GetWorkItems();
IncidentDataGrid.DataBind();

note that each code block here is almost identical and so could be
refactored further.. the only difference is the class you instantiate to
view the customer detail. This way, you're never saying this customer *is a*
Helpdesk customer, you're just saying they're a Customer, and the class
hierarchy exists only to provide an appropriate API to the data depending on
how you want to use it.

Of course this might be way off, and wildly inappropriate for what you want
to achieve.

And so the short answer to your question is... It depends what you want to
do. You may like some, all or none of these approaches. There's no *right*
way to define a class hierarchy per se. I see a lot of advice given,
articles, books, received wisdom on the subject etc that purports to have
the *right* way of doing things; of designing class hierarchies.. but almost
without exception (no pun intended) they're only right if the design suits
your purpose.
2) ... for example PrivateCustomer adds PrivateName
and LastName, and BusinessCustomer adds CompanyName (although I'm not
sure that this is good design in term of good OO practice, where
classes
should be derived if they have different behaviour, not data).
I disagree with this too. I don't think it's bad OO practice to have a
subclass which contains more specific data.
because in every
document, for example Invoice, you'd see fields like
"Company/Last Name: _________", which I don't like.
yeah - this sounds awful. Never do this. ;)

Leon
"Ahmed Salako" <Ahmed Sa****@discussions.microsoft.comwrote in message
news:83**********************************@microsof t.com...
Hiya,
what you might end up having is a class explosion. I will suggest
you
use interface that inherits from other interfaces. Like you can have
IPrivateCustomer, IBusinessCustomer, ICustomer. Your ICustomer Inherits
from
the IPrivateCustomer and IBusinessCustomer.

So you will have an implementation class called customer which implements
ICustomer, since your ICustomer interface inherits from different
interfaces,
you will explitcitly implement the other interfaces as well. So you can
dynamically at runtime cast your Customer class to those different
interface(s) when you need their certain properties, method or
functionality.
For example:

public interface IPrivateCustomer
{
string PrivateName { get; set; }
string PrivateAddress { get; set; }
}

public interface IBusinessCustomer
{
string CompanyName { get; set; }
}

public interface ICustomer : IPrivateCustomer, IBusinessCustomer
{
string FirstName { get; set; }
string LastName { get; set; }
}

public class Customer : ICustomer
{
//Explicity implements all methods/properties of the three interfaces.
}


Create an instance of the Customer Class here by doing the any or all of
following :
Customer customer = new Customer();

IPrivateCustomer privateCustomer = customer as IPrivateCustomer;
IBusinessCustomer businessCustomer = customer as IBusinessCustomer;
ICustomer iCustomer = customer as ICustomer;

The flexibility that you gain from this approach is that you only have a
single customer class and you can add new interface and remove others.

Also you may want to look at the Factory pattern, which will support the
creation of an object based on the type you supplied. You can use the
combination of the factory pattern with the simple scenario that i ahve
given.

I hope this work.

Cheers and Enjoy.
Jul 24 '08 #8
"his is a bit like the interface approach offered
earlier, but it doesn't require you to implement each interface in your
customer class"

The most response i have seen so far is i go with the class approach, and
none of them seem to provide detailed explanation about how its right.

Hi i appreciate your concern to solving the problem, but you seem to be
talking out of the problem scope. Is it wise to have different kinds of
class(es) for this scenario, if you must understand clearly, with interface,
you can stub a single instance of an object to multiple interfaces, so far
that object meets the contract. Interface is not a class, and its a very
powerful programming construct for dynamic polymorhism like this problem
area.
Can we all take a simple look at the .NET collection base classes and
interface,. I will give a very simple eye opener scenario here; and i hope
those who want to learn will learn :

1] IEnumerable is the base.
2] ICollection inherits from IEnumerable
3] IList inherits IEnumerable and ICollection
4] ArrayList implements from IList, ICollection, IEnumerable
Now my friends you can use an ArrayList as any of the following :

IEnumerable en = new ArrayList();
IList il = new ArrayList();
ICollection col = new ArrayList();

you have a single instance of ArrayList acting as different interfaces.

You can borrow these approach(es) for the problem at hand, i am not forcing
anyone, to embrace this superb approach but i am just concerned by how most
people tend to leave a cleaner approach for plumbing.

Follow this example again:
public interface IPrivateCustomer
{
string PrivateName { get; set; }
string PrivateAddress { get; set; }
}

public interface IBusinessCustomer
{
string CompanyName { get; set; }
}

public interface ICustomer : IPrivateCustomer, IBusinessCustomer
{
string FirstName { get; set; }
string LastName { get; set; }
}

public class ConcreteCustomer : ICustomer
{
public ConcreteCustomer()
{

}

public T GetCustomer<T>()
{
return ((T)(object)this);
}

public string FirstName
{
get
{
return "First Name";
}
set
{

}
}

public string LastName
{
get
{
return "Last Name";
}
set
{

}
}

public string PrivateName
{
get
{
return "Private Name";
}
set
{

}
}

public string PrivateAddress
{
get
{
return "Private Address";
}
set
{

}
}

public string CompanyName
{
get
{
return "Company Name";
}
set
{

}
}
}
Then with this example you can do any of the following :

ConcreteCustomer customer = new ConcreteCustomer();

IPrivateCustomer privateCustomer =
customer.GetCustomer<IPrivateCustomer>();
IBusinessCustomer businessCustomer =
customer.GetCustomer<IBusinessCustomer>();
ICustomer iCustomer = customer.GetCustomer<ICustomer>();
Jul 24 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: BCC | last post by:
Hi, I have a class with several member variables that should be initialized according to user input before an object is instantiated. Using a static variable is required here. But, I would...
3
by: Omer van Kloeten | last post by:
The Top Level Design: The class Base is a factory class with a twist. It uses the Assembly/Type classes to extract all types that inherit from it and add them to the list of types that inherit...
3
by: Erik Harris | last post by:
I apologize if this is a stupid question - I'm relatively new to OOP. I have a property that must exist in a class in order to be used by another class. The property, however, does not change with...
0
by: Edward Diener | last post by:
In Borland's VCL it was possible to divide a component into design time and run time DLLs. The design time DLL would only be necessary when the programmer was setting a component's properties or...
1
by: Stefan Richter | last post by:
Hi, I have to write a little program, to enter and retrieve data from a database. The most important aspect is that the code is easy to understand, clear and organized, and easy to modifiy or...
9
by: Grizlyk | last post by:
Somebody have offered std colors to C++ in the msg here: http://groups.google.com/group/comp.lang.c++/browse_frm/thread/2e5bb3d36ece543b/1acf6cd7e3ebdbcd#1acf6cd7e3ebdbcd The main objection to...
2
by: =?Utf-8?B?QmVu?= | last post by:
I have a Customer table in the database that relates to a CustomerType table (I have several other table combinations in the database like Document and DocumentType). As far as I can tell, I...
2
by: John | last post by:
Hi there, I am writing a simple program that will connect to database. Database has 2 tables, let's call them father and child. This is one to many relationship. I would like to create...
1
by: mattmao | last post by:
I am brand new to C#.NET so here is my trial on this lab exercise: using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace lab02exec { ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.