Help with OO Model

M

Marc De Schrijver

I'm designing an OO Model for a large application, and I have some question
on how to model a particular situation; it's not directly related to C# but
rather to general OO. The applicaiton will be developed in C# 2.0 though,
which may have some influence on the OO model.
Here's what I'm trying to model:

I have a class Company, a class Publisher, a class Manufacturer and a class
Distributor.
Their relationships are as follows:
1. A Publisher is a Company
2. A Manufacturer is a Company
3. A Distributor is a Company
6. A Company can be just a distributor
4. A Company can be just a publisher or a publisher and distributor at the
same time
5. A Company can be just a manufacturer or a manufacturer and distributor at
the same time
7. A Company can be a publisher, manufacturer and distributor all at the
same time

A Publisher and a Manufacturer are very similar in that they both create a
product; however, I think of the two roles differently and would prefer to
maintain them as different entity types. I would like to see code like
Publisher.Product when I'm dealing with printed material and
Manufacturer.Product when I'm dealing with non-printed material.
On the other hand, given a Product I would like to be able to return its
creator, which could be either a manufacturer or a publisher, depending on
the kind of product.

Any insights or recommendations are greatly appreciated.

-- Hans
 
D

Dave Sexton

Hi Marc,

I assume that you're stuck on inheritance chains?

It's probably worth mentioning first that a question like this won't get you
suitable answers without stating requirements of the application such as
those pertaining to the data model and business rules. Just stating that
one class can also be another doesn't really make too much of a difference
since there are so many other variables to be considered when architecting a
solution.

Secondly, and due to a lack of appropriate information, it's difficult to
say whether or not any of these entities should even be entities in the
first place. Maybe Company should just be an attribute on a Product class,
for instance. The question is, how normalized is your data model and is
there a real need for distinct state or the capability to process business
rules in a Company class?

Assuming that you really need an entity for each of the types you have
mentioned, you could create an abstract base class named, "Company", from
which any class can derive. Then create interfaces such as, IPublisher,
IManufacturer and IDistributer. Any class that derives from Company
(inheriting all of the base functionality) can also implement any of the
interfaces as well. Therefore, you could have classes such as
PublisherDistributer and PublisherManufacturerDistributor, etc.

Another option is to define interfaces such as, IProductProvider, which
could be implemented by IPublisher and IManufacturer, as per your example
where you'd like to code something like, "publisher.Product" or
"manufacturer.Product".

The level of granularity that you go defining interfaces and classes should
depend on the business rules and your versioning strategy, with what "seems"
correct being the least important, IMO. It's not just a matter of
recreating the real world out of objects, it's about what architecture would
allow you to accomplish your goals in the easiest, most flexible manner,
which is why analyzing the requirements would allow newsgroupers to offer
appropriate design patterns instead of arbitrary polymorphic techniques :)
 
K

Kevin Spencer

Hi Marc,

At first blush, it looks like you need to use a combination of inheritance
and interfaces. For example, your entities all have some functionality in
common, and that sounds like a base class "Company." As for Manufacturer,
Distributor, and Publisher, those sound like interfaces, which can allow for
mutltple "inheritance." So, in fact, you might actually have FOUR
interfaces:

ICompany - defines the properties and methods of any company
IManufacturer : ICompany - defines the properties and methods of a
manufacturer (inherits ICompany)
IDistributor : ICompany - defines the properties and methods of a
distributor (inherits ICompany)
IPublisher : ICOmpany - defines the properties and methods of a Publisher
(inherits ICompany)

Then you can create an abstract Company class which implements ICompany, and
has all of the base functionality built in. Every other class you derive
from it can implement 1 or more of the other interfaces in any combination.

--
HTH,

Kevin Spencer
Microsoft MVP
Bit Player
http://unclechutney.blogspot.com

Expect the unaccepted.
 
J

Joanna Carter [TeamB]

"Marc De Schrijver" <[email protected]> a écrit dans le message de
[email protected]...

| I'm designing an OO Model for a large application, and I have some
question
| on how to model a particular situation; it's not directly related to C#
but
| rather to general OO. The applicaiton will be developed in C# 2.0 though,
| which may have some influence on the OO model.
| Here's what I'm trying to model:
|
| I have a class Company, a class Publisher, a class Manufacturer and a
class
| Distributor.
| Their relationships are as follows:
| 1. A Publisher is a Company
| 2. A Manufacturer is a Company
| 3. A Distributor is a Company
| 6. A Company can be just a distributor
| 4. A Company can be just a publisher or a publisher and distributor at the
| same time
| 5. A Company can be just a manufacturer or a manufacturer and distributor
at
| the same time
| 7. A Company can be a publisher, manufacturer and distributor all at the
| same time
|
| A Publisher and a Manufacturer are very similar in that they both create a
| product; however, I think of the two roles differently and would prefer to
| maintain them as different entity types. I would like to see code like
| Publisher.Product when I'm dealing with printed material and
| Manufacturer.Product when I'm dealing with non-printed material.
| On the other hand, given a Product I would like to be able to return its
| creator, which could be either a manufacturer or a publisher, depending on
| the kind of product.

It looks to me that you need to use a class that accomodates Roles.

public class Role
{
}

public class Distributor : Role
{
}

public class Publisher : Role
{
}

public class Manufacturer : Role
{
}

public class Company
{
public List<Role> Roles {get...set...}

}

Using Publisher.Product implies that the Publisher can only produce one
Product.

Can I suggest that a Company has an Inventory property that is a managed
list of Products ?

But Product should have a Manufacturer, Publisher and Distributor property,
only if the Product is only ever related to one of any of those entities.
Otherwise, you should create a relationship class between the various roles
and a Product. This relationship is more an instance relationship rather
than a class relationship.

Does any of this make sense to you ?

Joanna
 
B

Bob Jones

The key to your problem is I think that you want to compose companies
dynamically, at run time in the client code. You really, really, really
do not want to create a class for every possible combination of
companies (and products?). Don't make things unmaintainable just for
the sake of a conceptual notion of pure inheritance. Besides one of the
priciples of OO design is "favor composition over inheritance."

Try this:
public class GenericCompany {
ArrayList AbstractCompany companyList;
ArrayList AbstractProduct productlist;

//all these should be implemented here. I'm too lazy.
public bool isA (string companyType); //kind of a pseudo-inheritance facade.
public AbstractCompany getCompanyByType (string companyType);
public AbstractCompany getCompanyByName (string companyName);
public void AddCompany ();
public void AddProduct();
}
public Publisher () : GenericCompany {
public void Publish();
}
.. . .

CLIENT
Publisher OJWhoDunItInc = new Publisher();
Distrubutor pusherManInc = new Publisher();
OJWhoDunItInc.AddCompany (pusherManInc);

Now you have a Publisher that is also a Distrubutor, so to speak. Not
in strict inheritance terms, but nonetheless you have multiple
companyTypes grouped as one. By iterating through the company
collection you can see if a given company "is a"(nother) (wink, wink)
kind of company. The HAS-A, composition, relationship vice inheritance
will allow you to flexibly create companies in client code. From the
client code perspective, all you have to do that you don't in
inheritance is to type cast the returned object from GetCompany();

I don't think you need to create the base class as abstract. You need
to implement all the methods that deal with the Arraylists in the base
in any case.

Another variation is to create an interface w/ all the common methods
declared; every company class implements this. In fact you can have an
interface with nothing declared in it! This is done just to be able to
treate all your classes as generic companies. Of course now any company
type can be treated as any other company type. This may not be as "type
safe" as you desire. And it does not allow you to do the unique things
of another type, it just allows you to get a handle on each companyType
in a generic way and do common things.
 
B

Bob Jones

"Favor composition over inheritance" is an OO design principle.

Do not create a class for each possible combination of companies!

Assuming you want a Publisher / Distributor to do both publisher and
distributor things, or any combination of companies, use composition.
This will allow you to dynamice create companies in your client code.

public class GenericCompany() {
ArrayList GenericCompany companyList;
ArrayList GenericProduct productList;

public bool isA (string companyType); // kind of a
pseudo-inheritance facade.
public GenericCompany getCompanyByType (string companyType);
public GenericCompany getCompanyByName (string companyName);
public void AddCompany(GenericCompany thiscompany);
public void AddProduct (GenericProduct thisProduct);
}
public class Publisher() : GenericCompany {
public void Publish();
}

CLIENT CODE

Publisher OJWhoDunItInc = new Publisher();
Distributer pusherManInc = new Distributor();

OJWhoDunItinc.AddCompany(pusherManInc);

if (OJWhoDunItInc.isA("Distributor") {
((Distributor)(OJWhoDunItInc.getCompany("Distributor"))).Distribute();
}

You could also create specific fields for each company type w/in the
GenericCompany, but an ArrayList will allow you to add new company
types w/out touching GenericCompany. (This also implies that you would
have to write isA() and GetCompany() using reflection.)

To make the addition of new company types in the future more flexible
you could use a factory design pattern. This means your existing
GenericCompany does not change at all. The factory pattern supports
other OO principle: "Depend on abstractions. Do not depend on concrete
classes." A "factory" may be just the thing for your Products, if you
have a lot and add more often.

To learn more about design patterns I HIGHLY recommend "Head First
Design Patterns." O'Reilly publishing. BTW, they're also a distributor!
 
B

Bob Jones

"Favor composition over inheritance" is an OO design principle.

Do not create a class for each possible combination of companies!

Assuming you want a Publisher / Distributor to do both publisher and
distributor things, or any combination of companies, use composition.
This will allow you to dynamice create companies in your client code.

public class GenericCompany() {
ArrayList GenericCompany companyList;
ArrayList GenericProduct productList;

public bool isA (string companyType); // kind of a
pseudo-inheritance facade.
public GenericCompany getCompanyByType (string companyType);
public GenericCompany getCompanyByName (string companyName);
public void AddCompany(GenericCompany thiscompany);
public void AddProduct (GenericProduct thisProduct);
}
public class Publisher() : GenericCompany {
public void Publish();
}

CLIENT CODE

Publisher OJWhoDunItInc = new Publisher();
Distributer pusherManInc = new Distributor();

OJWhoDunItinc.AddCompany(pusherManInc);

if (OJWhoDunItInc.isA("Distributor") {
((Distributor)(OJWhoDunItInc.getCompany("Distributor"))).Distribute();
}

You could also create specific fields for each company type w/in the
GenericCompany, but an ArrayList will allow you to add company types
w/out touching GenericCompany. (This implies that you would have to
write isA() and GetCompany() using reflection.)

To make the addition of new company types in the future more flexible
you could use a factory design pattern. This means your existing
GenericCompany does not change at all. The factory pattern supports
other OO principle: "Depend on abstractions. Do not depend on concrete
classes." A "factory" may be just the thing for your Products, if you
have a lot and add more often.

To learn more about design patterns I HIGHLY recommend "Head First
Design Patterns." O'Reilly publishing. BTW, they're also a distributor!
 
B

Bob Jones

Apologies for the multiple postings.

I wanted to add one more thing..... I noticed you said of products
"... I would like to return it's creator". Use Reflection.

Every object we create in C# inherits the GetType() method. This
method returns an instance of the Type (capital Tee) class. This class
is the basis of reflection. This class tells you everything you want to
know about the given object. What properties and methods it has, it's
inheritance chain, etc.

So in the example code where I show passing in a string:
xxx.GetCompany ("Distributor"), you can pass in the actual class type
(not the Distributor object mind you, just it's class type as extracted
from xxx.GetType()) and not have to deal w/ maintaining strings to
represent the various company classes.
 
M

Mark Wilden

Marc De Schrijver said:
I have a class Company, a class Publisher, a class Manufacturer and a
class
Distributor.
Their relationships are as follows:
1. A Publisher is a Company
2. A Manufacturer is a Company
3. A Distributor is a Company
6. A Company can be just a distributor
4. A Company can be just a publisher or a publisher and distributor at the
same time
5. A Company can be just a manufacturer or a manufacturer and distributor
at
the same time
7. A Company can be a publisher, manufacturer and distributor all at the
same time

If I were you, I'd identify more use cases before designing a data model to
support them. However, one possibility that occurs to me is to have
Publisher, Manufacturer, and Distributor point to a Company. But it's not
possible to know whether that would work without knowing what you actually
want to -do- with the data.
On the other hand, given a Product I would like to be able to return its
creator, which could be either a manufacturer or a publisher, depending on
the kind of product.

What do you want to do with the returned creator? Do you need to know
whether it is in fact a manufacturer or a publisher?

///ark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top