Lesson 4 - Birthday Reminder - Logic Layer

In the previous lesson, Birthday Reminder - Designing Forms, we designed all the forms for our application. In this tutorial, we're going to design the logical layer, that is, classes containing the application logic.

Person

We'll certainly work with people in our app, so let's create a class for them. Be sure to put the `public` modifier before the class name.

Properties

The person will have 2 properties: name and birthday. `Name` will be `string`, `Birthday` will be of the `DateTime` type. We're going to set these properties using a parametric constructor.

```public class Person
{
public string Name { get; set; }
public DateTime Birthday { get; set; }

public Person(string name, DateTime birthday)
{
Name = name;
Birthday = birthday;
}

}```

Methods

In addition to the constructor, the class will have `CalculateAge()` and `RemainingDays()` methods.

`CalculateAge()`

The method calculates and returns the person's current age in whole years. Unfortunately, this calculation isn't just about subtracting two dates, since `TimeSpan` can't determine the number of years, only the number of days. To calculate the age, we'll follow these steps:

1. We'll get the current date (without time) using `DateTime.Today`.
2. We'll calculate the age as the difference of the current date's and the birthday's years. You probably know that such age isn't accurate. If we were born on 2/1/1990 and today is 1/1/2010, we aren't 20 years old, but only 19. For this reason, we'll make a correction.
3. If the current date is before the date of birth plus the years we've calculated, the above case has occurred and we have to reduce the age by one year.
4. We'll return the final age we calculated.

The method's code looks as follows.

```public int CalculateAge()
{
DateTime today = DateTime.Today;
int age = today.Year - Birthday.Year;
age--;
return age;
}```

`RemainingDays()`

This method returns how many days remain until the person's birthday. Here's how to find out:

1. We'll get the current date (without time).
2. We'll get the next birthday by adding age + 1 to the date of birth.
3. We'll subtract the dates and return the total day difference. Since the difference is of the `double` type, we have to convert it to the `int` type.
```public int RemainingDays()
{
DateTime today = DateTime.Today;
DateTime nextBirthday = Birthday.AddYears(CalculateAge() + 1);

TimeSpan difference = nextBirthday - DateTime.Today;

return Convert.ToInt32(different.TotalDays);
}```

`ToString()`

Since we're going to list the people, we'll override the `ToString()` method to return the person's name:

```public override string ToString()
{
return Name;
}```

Person Manager

The next logical component of the application will be a person manager. The class will take care of all the people, will be able to add them, remove them, and save their list into a file and reload it. And finally, it'll be able to find the person with the nearest birthday among all the people.

Create a `PersonManager` class in the project and make it public.

Properties and Attributes

The only public property of the class will be a list of the people. The list will be of the `BindingList` type. We haven't met this collection type yet. It's a smarter `List` that can trigger a change event when its content changes. This mechanism automatically refreshes all the controls in a form that have this `BindingList` set as the data source. You can imagine that refreshing dozens of controls in a form manually after every change can be very confusing. Once we add a new person in our app, it'll be visible in the people list immediately without us having to refresh it from the code, it'll refresh itself. We'll initialize the `BindingList` in the constructor.

If we wanted to implement people editing, the `Person` class would need to implement the `INotifyPropertyChanged` interface. Any change (changing the name for example) would then be automatically reflected in all controls of all forms where this person appears. However, we won't be doing this here to keep things simple.

So far, the class looks like this:

```public class PersonManager
{
public BindingList<Person> People { get; set; }

public PersonManager()
{
People = new BindingList<Person>();
}

}```

Methods

In addition to adding and removing, the class will also be able to find the person with the nearest birthday. We'll discuss saving and loading people to/from a file later.

`Add()`

This method adds a new person to the `BindingList`. Since we use a form to add the person, it'll be useful if the method took the person's properties as parameters and created a new instance based on those. From the date of birth we'll only save the date part, without the time.

Before adding the person, we'll make sure the name isn't too short and the date entered isn't in future. If any of these situations occur, we'll throw an exception. Exceptions are the right way to handle errors in object-oriented applications.

Exceptions are explained in more detail in Working with Files in C# .NET. If you haven't met those yet, you only need to know that we throw an exception using the `throw` keyword, followed by the exception instance. There are several types of exceptions, and we can also create our own. In our case, we can use `ArgumentException`. We enter the error message as a parameter of the exception constructor. Once the exception is thrown, the method no longer continues. We're going to handle the error later when we'll call the method from the form.

```public void Add(string name, DateTime birthday)
{
if (name.Length < 3)
throw new ArgumentException("Name is too short");
if (birthday.Date > DateTime.Today)
throw new ArgumentException("Birthday must not be in future");
Person person = new Person(name, birthday.Date);
}```

`Remove()`

This method removes a person from the `BindingList`. Since we always want to remove an already completed person, this method takes the person instance as a parameter.

```public void Remove(Person person)
{
People.Remove(person);
}```

`FindNearest()`

This method finds and returns the person with the nearest birthday. To find the person in the collection, we'll use the LINQ `OrderBy()` method to order people by how many days remain until their birthday. We'll store the result in a collection which type we're not going to specify and use the `var` keyword instead, as is customary with LINQ. Then we'll return the first person. We should only call the method if there are people in the collection. Although it should be clear from the code what the method does, you can, of course, look at the tutorials in the Collections and LINQ course, where LINQ is described in more detail.

```public Person FindNearest()
{
var sortedPeople = People.OrderBy(p => p.RemainingDays());
return sortedPeople.First();
}```

We'll continue in the next lesson, Birthday Reminder - Wiring the Presentation and Logic Layers, to get the app up and running. The current source code is available to download below.

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Application includes source codes in language C#

Article has been written for you by David Capka
User rating: