More adventures in learning OOP

R

RSH

I am exploring OOP and I am trying to get a grasp on the basics. Below is
the code that creates a basic Person with basic properties.

I also have an Orders Class where Orders are made by Persons. I am having
trouble figuring out how to "connect" the two so that when a new Order is
created I can specify the Person that it belongs to.

Here is the code...how do I go about making an Order belong to a Person...or
am I way off base here?

Thanks!
Ron



using System;

using System.Collections.Generic;

using System.Text;

namespace ClassTesting

{

public class Person

{

private string firstName;

private string lastName;

private Address mailingAddress;

private Address billingAddress;

private Address shippingAddress;

private Phone homePhone;

private Phone cellPhone;

public Person()

{

this.mailingAddress = new Address();

this.billingAddress = new Address();

this.shippingAddress = new Address();

this.homePhone = new Phone();

this.cellPhone = new Phone();

}

public Address ShippingAddress

{

get { return shippingAddress; }

}

public Address BillingAddress

{

get { return billingAddress; }

}

public Address MailingAddress

{

get { return mailingAddress; }

}

public Phone HomePhone

{

get { return homePhone; }

}

public Phone CellPhone

{

get { return cellPhone; }

}

public string LastName

{

get { return lastName; }

set { lastName = value; }

}

public string FirstName

{

get { return firstName; }

set { firstName = value; }

}

}

public class Address

{

private string line1;

private string city;

private string state;

private string postalCode;

public string PostalCode

{

get { return postalCode; }

set { postalCode = value; }

}

public string State

{

get { return state; }

set { state = value; }

}

public string City

{

get { return city; }

set { city = value; }

}

public string Line1

{

get { return line1; }

set { line1 = value; }

}

}

public class Phone

{

private int areaCode;

private int prefix;

private int postfix;

private int extension;

public int AreaCode

{

get { return areaCode; }

set { areaCode = value; }

}

public int Prefix

{

get { return prefix; }

set { prefix = value; }

}

public int Postfix

{

get { return postfix; }

set { postfix = value; }

}

public int Extension

{

get { return extension; }

set { extension = value; }

}

public string PhoneNumber

{

get { return "(" + this.AreaCode.ToString() + ")" + this.Prefix.ToString() +
"-" + this.Postfix.ToString(); }

}

}







public class Orders

{

private int orderNumber;

private DateTime orderDate;

private string quantity;

private string product;

public int OrderNumber

{

get { return orderNumber; }

set { orderNumber = value; }

}

public DateTime OrderDate

{

get { return orderDate; }

set { orderDate = value; }

}

public string Quantity

{

get { return quantity; }

set { quantity = value; }

}

public string Product

{

get { return product; }

set { product = value; }

}

}

}
 
C

Chris Dunaway

What you probably need is a property in your order called (for example)
OrderedBy which is of type Person.

When you create your order, you would assign the Person property to be
the instance of the Person placing the order.
 
P

Peter Rilling

There are usually two ways of defining ownership. Depending on your needs,
you can use either one or both.

1) If an order belongs to only a single person, then you can pass an
instance of the person into the constructor for the order then provide a
proeprty to access the owner. This way the order knows who owns it. This
allwos you to go from order to person without a lot of work.

public class Order{
public Order( Person owner ){...}

public Person Owner{get{...}}

private Order m_owner = null;
}

2) You can provide a collection (or some list) in the Person class that
contains a list of all orders. This allows you to go from person to orders.
Below is a generic list, but you can always make it strongly typed by
creating your own collection or using generics.

public class Person{
public ArrayList Orders {get{...}}

private ArrayList m_orders = new ArrayList();
}


Now, with the above, you can do something like:

Person myPerson = new Person();
myPerson.Orders.Add(new Order(myPerson));


Variations on this exist, but these are the two primary ways to maintain
relationships.
 
S

Steven Nagy

In this instance, i think BAD means GOOD...

Check out the rules of normalisation for databases as well. The theory
is kind of the same for what you are doing.
Helps you relate different data.
 
J

Joanna Carter [TeamB]

"RSH" <[email protected]> a écrit dans le message de %[email protected]...

| I am exploring OOP and I am trying to get a grasp on the basics. Below is
| the code that creates a basic Person with basic properties.
|
| I also have an Orders Class where Orders are made by Persons. I am having
| trouble figuring out how to "connect" the two so that when a new Order is
| created I can specify the Person that it belongs to.
|
| Here is the code...how do I go about making an Order belong to a
Person...or
| am I way off base here?

You need to change your Orders class :

First, change the name; Orders signifies more than one, you should only ever
use singular nouns if you are not modelling a list.

Then declare an Order Line class (assuming an Order could be for more than
one item :

public class OrderLine
{
private string quantity;
private string product;
private float unitPrice

public string Quantity
{
get { return quantity; }
set { quantity = value; }
}

public string Product
{
get { return product; }
set { product = value; }
}

public string UnitPrice
{
get { return unitPrice; }
set { unitPrice = value; }
}

public float Total
{
get { return quantity * unitPrice; }
}
}

Now you can declare your Order class :

public class Order
{
private string orderRef; // strings are preferable in case pre/suf/fixes
are required
private DateTime orderDate;
private Customer customer;
private List<OrderLine> lines = new List<OrderLine>()

public string OrderRef
{
get { return orderRef; }
set { orderRef = value; }
}

public DateTime OrderDate
{
get { return orderDate; }
set { orderDate = value; }
}

public Customer Customer
{
get { return customer; }
set { customer = value; }
}

public OrderLine AddLine()
{
OrderLine newItem = new OrderLine();
lines.Add(newItem);
return newItem;
}

public void RemoveLine(OrderLine item)
{
lines.Remove(item);
}

public void RemoveLine(int index)
{
lines.RemoveAt(index);
}

public int LineCount
{
get { return lines.Count; }
}

public OrderLine GetLine(int index)
{
return lines[index];
}

public Enumerator<OrderLine> Lines
{
return lines.GetEnumerator();
}

public float Total
{
get
{
float result = 0.0;
foreach (OrderLine line in lines)
result += line.Total;
return result;
}
}
}

Note that the lines field is not directly surfaced as a public property.
This is to enforce the idea of Composition, where a containing object is
responsible for its contained objects; the contained objects do not have a
context outside of the containing object and their lifetimes are governed
solely by the containing object.

In order to add lines, you have to ask the Order for a new line and you have
to ask the Order to remove any unwanted lines; this reinforces the concept
that an Order contains lines and is responsible for their "lives".

Joanna
 
J

Joanna Carter [TeamB]

"Peter Rilling" <[email protected]> a écrit dans le message de [email protected]...

| 1) If an order belongs to only a single person, then you can pass an
| instance of the person into the constructor for the order then provide a
| proeprty to access the owner. This way the order knows who owns it. This
| allwos you to go from order to person without a lot of work.

Although I would agree that passing an "owner" to a constructor, this would
be unusual in the scenario we are contemplating of a Sales Order and
Customer. It is much pore usual to have a read/write property than the
constructor and a read-only property.

Another point is that an Order can be for either a Person or just as likely,
a Company.

To accomodate this, you have to design a relationship between Customer,
Person and Company. Now the first instinct can be to have a Customer class
and derive Person and Company from it, thus allowing us to assign either a
Person or a Company to a Customer property. Unfortunately, this then gives
us a situation where a Person *has* to be a Customer; something which may
not always be true. There is also the possibility that either a Person or a
Company may not just be a Customer, but a Supplier as well.

To reolve this complexity, you cannot use a single simple relationship;
instead you have to use a slightly more complex hierarchy :

class Person // details relating to being a person

class Company // details relating to being a company

interface Customer // behaviour relating to being a Customer

class PersonalCustomer : Person, ICustomer

class CorporateCustomer : Company, ICustomer

class Supplier : Company // business rule says that a Supplier must be a
company

class Order
{
Customer: ICustomer;
...
}

There could be other variations on this hierarchy; this is my instinctive
first cut :)

| 2) You can provide a collection (or some list) in the Person class that
| contains a list of all orders. This allows you to go from person to
orders.
| Below is a generic list, but you can always make it strongly typed by
| creating your own collection or using generics.
|
| public class Person{
| public ArrayList Orders {get{...}}
|
| private ArrayList m_orders = new ArrayList();
| }

At first glance this seems like a good idea but you may also consider that
this now implies that all Persons have to have Orders. This then means that
you cannot have a Person who is a Supplier or other relationship without
also being a Customer.

The idea of 1-n relationships like Customer-Orders tends to be based on the
RAD database concepts of master-detail grids where selecting a Customer in
one grid changes the items shoiwn in the detail grid. However this is not
always a very good model when it comes to object relationships.

Instead, this kind of direct relationship is best resolved by looking at
real life and modelling classes on that. In the real world, you would not
ask a Customer for a list of Orders, that could imply that you would either:
get a list of all the Customer's Orders whether they were for your Company
or not, or that the Company didn't keep a record of Orders issued to that
Customer and had to rely on the Customer to keep their records :)

Most Companies have a Sales Ledger and that is the correct place in the
system where a relationship between a Customer and an Order is made; every
time a Customer places an Order, an Entry is added to the Sales Ledger that
contains a reference to the Customer and the Order. So we end up with teh
following additional classes :

class LedgerItem
{
...
public ICustomer Customer {...}

public Order Order {...}
...
}

class SalesLedger
{
private items List<LedgerItem>;
...

public LedgerItem Add(Customer customer, Order order)
{
LedgerItem newItem = new LedgerItem(customer, order);
items.Add(newItem);
return newItem;
}

public List<Order> GetOrdersForCustomer(ICustomer customer)
{
// build list of Orders filtered by Customer
}

// other methods and properties that allow retrieval of items by Date,
Product, etc
}

Notice that items can be added or retrieved but never removed; this is in
accordance with the concept of having an Audit Trail that ensures that items
cannot be "hidden" from an auditing process carried out for legal reasons.

Just a few ideas that may clarify how object domains can be correctly
modelled :)

Joanna
 
R

RSH

This is great stuff. I greatly appreciate everyones contributions.

Thank you all!

RSH


Joanna Carter said:
"RSH" <[email protected]> a écrit dans le message de %[email protected]...

| I am exploring OOP and I am trying to get a grasp on the basics. Below
is
| the code that creates a basic Person with basic properties.
|
| I also have an Orders Class where Orders are made by Persons. I am
having
| trouble figuring out how to "connect" the two so that when a new Order
is
| created I can specify the Person that it belongs to.
|
| Here is the code...how do I go about making an Order belong to a
Person...or
| am I way off base here?

You need to change your Orders class :

First, change the name; Orders signifies more than one, you should only
ever
use singular nouns if you are not modelling a list.

Then declare an Order Line class (assuming an Order could be for more than
one item :

public class OrderLine
{
private string quantity;
private string product;
private float unitPrice

public string Quantity
{
get { return quantity; }
set { quantity = value; }
}

public string Product
{
get { return product; }
set { product = value; }
}

public string UnitPrice
{
get { return unitPrice; }
set { unitPrice = value; }
}

public float Total
{
get { return quantity * unitPrice; }
}
}

Now you can declare your Order class :

public class Order
{
private string orderRef; // strings are preferable in case pre/suf/fixes
are required
private DateTime orderDate;
private Customer customer;
private List<OrderLine> lines = new List<OrderLine>()

public string OrderRef
{
get { return orderRef; }
set { orderRef = value; }
}

public DateTime OrderDate
{
get { return orderDate; }
set { orderDate = value; }
}

public Customer Customer
{
get { return customer; }
set { customer = value; }
}

public OrderLine AddLine()
{
OrderLine newItem = new OrderLine();
lines.Add(newItem);
return newItem;
}

public void RemoveLine(OrderLine item)
{
lines.Remove(item);
}

public void RemoveLine(int index)
{
lines.RemoveAt(index);
}

public int LineCount
{
get { return lines.Count; }
}

public OrderLine GetLine(int index)
{
return lines[index];
}

public Enumerator<OrderLine> Lines
{
return lines.GetEnumerator();
}

public float Total
{
get
{
float result = 0.0;
foreach (OrderLine line in lines)
result += line.Total;
return result;
}
}
}

Note that the lines field is not directly surfaced as a public property.
This is to enforce the idea of Composition, where a containing object is
responsible for its contained objects; the contained objects do not have a
context outside of the containing object and their lifetimes are governed
solely by the containing object.

In order to add lines, you have to ask the Order for a new line and you
have
to ask the Order to remove any unwanted lines; this reinforces the concept
that an Order contains lines and is responsible for their "lives".

Joanna
 
J

Joanna Carter [TeamB]

"RSH" <[email protected]> a écrit dans le message de (e-mail address removed)...

| > public class OrderLine
| > {
| > private string quantity;
...
| > public string Quantity
| > {
| > get { return quantity; }
| > set { quantity = value; }
| > }

Heheh, did anyone else spot the deliberate mistake ?

public class OrderLine
{
private int quantity;
...
public int Quantity
{
get { return quantity; }
set { quantity = value; }
}

<sheepish grin>

Joanna
 
R

RSH

Jo,

I am getting an error "A get or set accessor expected."

public Enumerator<OrderLine> Lines

{

return lines.GetEnumerator();

}





If I modify it I get the error "Error 1 The type or namespace name
'Enumerator' could not be found (are you missing a using directive or an
assembly reference?) "

public Enumerator<OrderLine> Lines

{

get { return lines.GetEnumerator(); }

}



I really can't find anything that is helping me resolve this.



Thanks,

Ron
 
J

Joanna Carter [TeamB]

"RSH" <[email protected]> a écrit dans le message de (e-mail address removed)...

| I am getting an error "A get or set accessor expected."

| If I modify it I get the error "Error 1 The type or namespace name
| 'Enumerator' could not be found (are you missing a using directive or an
| assembly reference?) "
|
| public Enumerator<OrderLine> Lines
| {
| get { return lines.GetEnumerator(); }
| }

Well; you must be learning because you got that bit right :))

Now, the other problem will be because I should have specified the method
correctly :

public List<OrderLine>.Enumerator Lines
{
get { return lines.GetEnumerator(); }
}

Sorry about that but Outlook Express doesn't have a C# parser built in :))

Joanna
 
R

RSH

Thank you so much for your help. This really has been a very beneficial
learning experience.

I have been messing around with adding Orders and Orderlines etc. This is
way powerful...my poor head is spinning with all the possibilities.

Ron
 
J

Joanna Carter [TeamB]

"RSH" <[email protected]> a écrit dans le message de %[email protected]...

| Thank you so much for your help. This really has been a very beneficial
| learning experience.
|
| I have been messing around with adding Orders and Orderlines etc. This is
| way powerful...my poor head is spinning with all the possibilities.

Now for your next lesson... :)

It would be good if you used your knowledge so far to attempt to design a
Sales Ledger class as I discussed in an earlier message.

Try to determine what functionality you need to show and that which you need
to hide internally. Then I would be very interested to see how you manage.
Don't forget that you may need other support classes as well.

Joanna
 
R

RSH

I will...that is a great idea.

I do have one question regarding this part of the code:
public List<OrderLine>.Enumerator Lines

{

get { return lines.GetEnumerator(); }

}



What does this do? What is it called? and how do I use it?

I appreciate you mentoring me, dealing with a newbie :)

Thanks,

Ron
 
J

Joanna Carter [TeamB]

"RSH" <[email protected]> a écrit dans le message de (e-mail address removed)...

| I do have one question regarding this part of the code:
| public List<OrderLine>.Enumerator Lines
| {
| get { return lines.GetEnumerator(); }
| }
|
| What does this do? What is it called? and how do I use it?

This is a method that returns an iterator or enumerator that allows you to
traverse the collection without having access to the whole list
functionality like Add, Remove, etc; all of which should not be allowed as
the list is meant to be managed by the Order of which it is a part.

You could also use ReadOnlyCollection<T> to allow inspection, of the items
in a list without allowing modification of the list itself.

public ReadOnlyCollection<OrderLine> Lines
| {
| get { return new ReadOnlyCollection(lines); }
| }

There are two different type of aggregation: Aggregation itself and
Composition.

Aggregation typifies an object holding a list of related objects, but those
contained objects have a life of their own outside of the containing object.
e.g. a Company may have a list of Employees who are of the type Person in
the role of Employee; if the Company closes, the Employee list might be
destroyed but the Persons still exist and can be used again in another
context.

Composition typifies an object holding a list of objects whose lifetimes are
governed by the containing object. In the example of the Sales Order, Order
Lines have no context outside of the Order of which they are a part. Without
the Order, the Lines have no raison d'être, therefore thay are destroyed
when the Order is destroyed. Classes like ReadOnlyCollection allow us to see
the list, even to modify an individual item, but without being able to
modify the list itself.

Joanna
 

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