I have a question regarding OOP composition.
Let's say that a mother has 0 or plus children, and a child has one and only one biologic mother.
To illustrate it, I did the following :
public class Mother : ObservableObject
{
// [...]
ObservableCollection<Child> Children {get; set;}
}
public class Child : ObservableObject
{
public Child(Mother mother)
{
this.Mother = mother;
// Adding the child to the mother's children collection
mother.Children.Add(this);
}
public Mother Mother {get; set;}
}
but I wonder if it's okay to automatically add the child to the mother's collection, or if I should go with the following :
Mother mother = new Mother();
Child child = new Child(mother);
mother.Children.Add(child);
Thanks :)
I'd prefer,
public class Mother : ObservableObject
{
// ...
public Child GiveBirth()
{
var newBorn = new Child(this);
this.Children.Add(newBorn);
return newBorn;
}
// ...
}
I think the modeling is a little off. A Mother and a Child are semantically related to one another, but they're instances of the same object. They are both a Person.
The creation of a Person is an operation performed by a Person. So a Person shouldn't even have a public constructor, but rather a factory method which takes care of this logic. Something like this:
public class Person : ObservableObject
{
private Person()
{
Children = new ObservableCollection<Person>();
}
public Person Mother { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate()
{
var child = new Person();
child.Mother = this;
this.Children.Add(child);
return child;
}
}
This modeling is still a bit limited, for example we're only talking about asexual reproduction here. So we're not effectively modeling humans yet. Perhaps we need to add a father?
public class Person : ObservableObject
{
private Person()
{
Children = new ObservableCollection<Person>();
}
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate(Person father)
{
var child = new Person();
child.Mother = this;
child.Father = father;
this.Children.Add(child);
father.Children.Add(child);
return child;
}
}
We'll want to add some checking for nulls and whatnot of course. Now we've also discovered that we need to specify genders. (While family structures may vary considerably, the act of creating a person is pretty well established.) So we can keep adding features like that. At some point we may indeed subclass these, but those subclasses will likely end up being mostly semantic pass-through objects with hard-coded default values for this Person superclass.
But just for fun, let's try adding genders...
public class Person : ObservableObject
{
private Person(Sex gender, Person mother, Person father)
{
// TODO: Check for null mother and father
this.Gender = gender;
this.Mother = mother;
this.Father = father;
Children = new ObservableCollection<Person>();
}
public Sex Gender { get; private set; }
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate(Person father)
{
// TODO: Check for null father, confirm gender of father
var child = new Person(PickRandomGender(), this, father);
this.Children.Add(child);
father.Children.Add(child);
return child;
}
private Sex PickRandomGender() { /.../ }
public enum Sex
{
Female,
Male
}
}
Ok, that was fun. Cleaned up a little bit by moving some logic to the constructor as well. But now there's another problem... fathers can procreate. Which sounds kind of painful. Now it looks like we're ready to subclass:
public class Person : ObservableObject
{
protected Person(Sex gender, Person mother, Person father)
{
// TODO: Check for null mother and father
this.Gender = gender;
this.Mother = mother;
this.Father = father;
Children = new ObservableCollection<Person>();
}
public Sex Gender { get; private set; }
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
protected Sex PickRandomGender() { /.../ }
public enum Sex
{
Female,
Male
}
}
public class Woman : Person
{
// TODO: Override Gender with a hard-coded value
public Person Procreate(Person father)
{
// TODO: Check for null father, confirm gender of father
var child = new Person(PickRandomGender(), this, father);
this.Children.Add(child);
father.Children.Add(child);
return child;
}
}
(Should we subclass a Man as well? It semantically seems cleaner, but are there any operations or attributes specific to men that aren't shared by women? Perhaps, but our models aren't that detailed yet.)
Looking back, the classes of Mother and Child seem kind of limited and short-sighted at this point. A woman isn't necessarily a mother, and all people are children. As you can imagine, there are plenty of features to add to this system. But following the same general process of building out the domain like this should accommodate that.
Suppose you have a class name building. This class building has a function called BuildRooms(). There is another class Room having functions to make rooms. You create objects of class Room as r1, r2,r3 etc. Now this building has 3 rooms. We can open doors and close doors methods inside Room class. Building class is composed of Rooms. It means this building has 3 rooms. Write code in any language you prefer. This is composition. Building has rooms so it is Has-A relationship.
class building{
void make_rooms()
{
room r1=new room(), r2=new room();
r1.open();
r2.close();
}
}
class room{
void open()
{
}
void close()
{
}
}
Related
I am experimenting with classes and was wondering if it is possible to link classes depending on a boolean value within one of the classes. I have a Person class and a field is private 'boolean value HasPet'. So if a person has a pet then I would like for a pet object to be made and link the classes together. Is this possible. I am completely new to classes. Would I have to make an ID field and link them like that?
static void Main(string[] args)
{
Person Teacher = new Person("Phoebe", 32, "brown", "hazel", true);
}
public class Person
{
private string Name;
private int Age;
private string HairColour;
private string EyeColour;
private bool HasPet;
public Person(string name, int age, string hairColour, string eyeColour, bool hasPet)
{
Name = name;
Age = age;
HairColour = hairColour;
EyeColour = eyeColour;
HasPet = hasPet;
}
public void ChangePetStatus()
{
Console.Write($"We heard that your pet status has changed...");
if (HasPet == true)
{
Console.WriteLine("we are sorry to hear that. Pet status has been changed.");
HasPet = false;
}
else
{
Console.WriteLine("that's great. A pet is a lovely addition to the household. Pet status has been changed.");
HasPet = true;
}
}
public void Greetings()
{
Console.WriteLine($"Hello my name is {Name} and I am {Age} years old. I have {HairColour} hair and {EyeColour} eyes. It is {HasPet} that I have a pet.");
}
}
My suggestion would be to reevaluate what inheritance means, if we look into Microsoft's definition
Inheritance is one of the fundamental attributes of object-oriented
programming. It allows you to define a child class that reuses
(inherits), extends, or modifies the behavior of a parent class. The
class whose members are inherited is called the base class. The class
that inherits the members of the base class is called the derived
class.
In your case I would say that inheritance has nothing to do with Person and the referred Pet class as neither of them will be inheriting or reusing each other's members, if you or the task insists on using inheritance for this case you'll need some other class that groups Person and Pet by similar properties for example LivingBeing which could have functions Respire(), Move() etc..
I would say make a many to many relationship(or one to many, if it's a specific case and Pet can't have more than one Person as owner), where Person could have many Pets and Pet could have many Persons as owners.
classes which I would suggest are:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string HairColour { get; set; }
public string EyeColour { get; set; }
public IEnumerable<PersonPet> PersonPets { get; set; }
}
public class PersonPet
{
public int PersonId { get; set; }
public int PetId { get; set; }
}
public class Pet
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public IEnumerable<PersonPet> PetPersons { get; set; }
}
Where you would not need any inheritance or HasPet field as you can determine whether Person has a Pet or not by PersonPets.
EDIT:
As suggested in subcomments by #Ralf this is a relational view on current problem and classes could be subject to change. The main point is that, to link Person and Pet, using inheritance is not a right way. At least in the context which author provided
I have a base class with a public property.
public class Parent
{
public string Name {get; set;}
}
I want that field will be calculated in the child constructor
public class Child1 : Parent
{
public Child1(string a, string b)
{
this.Name = a + " " + b;
}
}
And I want to mask or decrease visibility of Name in the child.
That we will not be able to do
var l = new Child1("aa", "bb");
l.Name = "something else";
I am pretty sure that what I am trying to achieve is impossible and against Liskov substitution principle.
Any idea about this?
This sounds less like a parent/child relationship or another case of Polymorphy.
I do not know of a accesor that would say "public in this class, but not inheritors". And not just for C#, but any OOP langauge I learned.
It sounds more like a a case for encapsulation:
public class Child1 {
Parent _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
}
One of the first things you learn in MVVM: If polymorphy can not do that or you do not have enough control over the class, just encapsulate it into something you do have full control over.
Edit:
In a more advanced view, with a abstract base class:
public abstract class Person {
public string Name {get; set;}
}
public class Parent : Person {
//I know of no property parent could have, that person does not
//Even the concept of a parent name, sounds more like a "Person" thing
}
public class Child1 : Person {
Parent _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
}
Alternatively, just make one class:
public class Person {
//Every person has a parent
Person _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
//And of course it's own name
public string Name {get; set;}
}
Why not passing name to Parent constructor like that?
public class Parent
{
public string Name { get; private set; } // private set; can be skipped
public class Parent(string name)
{
Name = name;
}
}
Then Child class would look like this
public class Child : Parent
{
public Child(string a, string b)
: base(a + b)
{ }
}
If you are not able to make change in base class there is alternative solution (partially only)
public class Parent
{
public string Name { get; set; }
}
public class Child : Parent
{
public new string Name
{
get => base.Name;
private set => base.Name = value;
}
public Child(string a, string b)
{
Name = $"{a} {b}";
}
}
But there is quick workaround for encapsulation...
Child c = new Child("abc", "def");
c.Name = "New name"; // this will cause compilation error
Parent p = c; // this is perfectly legal
p.Name = "HACKED!";
I have a class Person (Parent class) which contains some properties. Let's say 2 properties. I want to access 1 properties out of 2 properties in Student (child class) from Person class(Parent class).
Note: All properties are public which I need to use in other child class.
How will I achieve that using C#? (This applies to any object oriented programming languages)
Below is my sample code.
using System;
public class Person
{
public string name; //only want this property in all child classes
public float salary; //don't want to access this property in Student
}
public class Student: Person
{
public string subject;
}
public class Employee: Person
{
public int employeeId;
}
You shouldn't have salary as a field in Person unless all Persons have a salary,
this should instead go in the Employee class, or the highest class which uses salary
There is a conceptual problem in your code! The salary property is not general enough to be in the person class (not every person has a salary). You should not include this property in the Person class.
Using an interface would help only if:
you have multiple subclasses and some of them have salaries
you need to manage the subclasses that have salaries as a group without knowing the particular type of each one (e.g. polymorphism).
Hope that helps!
You can use an interface to achieve what you are aiming for. It doesn't stop the compiler from creating a Salary property for student object. But by using IStudent, you can restrict the access of the end user.
public class Person
{
public string Name { get; set; } //only want this property in all child classes
public float Salary { get; set; } //don't want to access this property in Student
}
interface IStudent
{
string Name { get; set; }
string Subject { get; set; }
}
public class Employee : Person
{
public int EmployeeId { get; set; }
}
public class Student : Person, IStudent
{
public string Subject { get; set; }
}
class Program
{
static void Main(string[] args)
{
IStudent s = new Student() { Name = "Student1", Subject = "Subject1" };
Console.WriteLine(s.Name);
}
}
I am designing a c# class and would like to know if my design is right.
abstract class PersonBase
{
public string Name { get; set; }
public PersonBase Parent { get; set; }
public List<PersonBase> Children { get; set; }
}
class Person : PersonBase
{
//public override List<Person> Children { get; set; }
public Person()
{
Children = new List<PersonBase>();
}
public void Add(Person child)
{
child.Parent = this;
Children.Add(child);
}
}
test code:
private void button1_Click(object sender, EventArgs e)
{
Person parent = new Person();
parent.Name = "parent";
Person child = new Person();
child.Name = "child1";
child.Add(new Person() { Name = "grandchild1" });
parent.Add(child);
}
It works as expected. I am able to access the parent children objects from anywhere in the hierarchy. My concern is it looks recursive or circular reference (can't find the right word here).
Here is what I did finally:
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; private set; }
public Person()
{
Children = new List<Person>();
}
public void AddChild(Person child)
{
if (child == this) { return; }
if (Children.Contains(child)) { return; }
child.Parent = this;
Children.Add(child);
}
}
Like #LukeH asked your break out of BasePerson and Person do not make sense. This will work just fine.
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public IList<Person> Children { get; private set; }
public Person()
{
Children = new List<Person>();
}
public void Add(Person child)
{
child.Parent = this;
Children.Add(child);
}
}
If you are going to have different kinds of Person then you might want to break you stuff out into an Interface if there is not inherited logic and an abstract class if you want to provide some default logic.
EDIT: Adding expressed issues from Danny
It could become a problem if you used child.Add(Me or MyParent or ancestor). Then it would be an endless loop of references. You might want to add code in the Add method to prevent improper usage so a 'Person' can not add itself or it's parents as a child.
The base class seams redundant, also, you are assuming children is not null and assigning in constructor, yet it has a public setter.
Change children's setter to private or protected and don't worry about circular reference - just mark parent property with an attribute to prevent it from being serialized.
//Declare and initialize Person a, b, c;
a.Add(c);
b.Add(c); // Now a thinks c is a child, but c does not think a is a parent!
You need some sort of validation, perhaps that c doesn't already have a parent, or set the parent/child only in a Parent.CreateChild method. Or allow it to have multiple parents.
(Also, I would declare the method AddChild, since that's what it's doing. And also pay attention to the design considerations from other commenters.)
Perhaps this:
class Person
{
public string Name { get; private set; }
public Person Parent { get; private set; }
public IList<Person> Children { get; private set; }
private Person() {} // Private constructor
public static Person CreatePersonNoParent(string name){*implementation elided*};
public Person CreateChild(string name)
{
Person child = new Person { Name=name, Parent=this };
this.Children.Add(child);
return child;
}
}
Let's say I have the following two classes:
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
public class Customer: Person
{
public string CustomerNumber { get; set; }
public string PaymentTerms { get; set; }
}
Now, if I have a person that I want to make a customer, I have, to the best of my knowledge, three options, and I'm hoping for advice on which is the best and on any other options, maybe using the new dynamics stuff in C#4.
I can add a constructor or property to Customer that takes a Person and assigns values to the base class, e.g.
public Customer(Person person)
{
base.Name = person.Name;
base.Address = person.Address;
}
or I can implement an untidy set accessor like this:
public Person Person
{
set
{
Name = value.Name;
Address = value.Address;
}
}
or I can aggregate Person into Customer like this:
public class Customer
{
public Person Person { get; set; }
public string CustomerNumber { get; set; }
public string PaymentTerms { get; set; }
}
The last is to me the neatest, except for always having to e.g. access Customer.Person.Name, instead of just Customer.Name.
I would personally go for composition, yes (your last option). Note that you can always provide "helper properties":
public string Name { get { return Person.Name; } }
Indeed, you can do this for all the properties you want, and never expose the Person property to the outside world at all.
On the other hand, inheritance is useful if you want to be able to treat a Customer as a Person - passing it to methods with a Person parameter, for example. I usually accomplish that sort of thing with interfaces though; you could have an IPerson interface implemented by both Customer and Person. Inheritance introduces all sorts of design decisions which simply don't come up (or are a lot simpler) when you don't get into inheritance.
I'd either use the constructor, or maybe a factory method, like
public static Customer CreateFromPerson(Person person)
{
return new Customer(){ Name = person.Name }//etc...
}
I don't like the setter as you're not actually setting the 'Person' on a customer, and I don't like the last option because it leads to a Law of Demeter (LOD) violation when you access the person through the customer (customer.person.name etc).