Programming using C# LECTURE 10 Object Composition Interfaces Collections Covariance Object class What’s to come today? • Object Composition • Collections • • • Dictionaries Queues Stacks • Interfaces • • IComparable<T> - Sorting collections IComparer<T> - Writing our own comparer • Covariance • Object class Object Composition • Object composition is a way of combining multiple simple objects to create a more complex object. • We typically use the HAS-A relationship to check whether one object should be composed within another. • An example of object composition, would be a Bathroom HAS-A Tub. So Tub, may be a property of the Bathroom class. Object Composition Ex. public class Bathroom { public Tub tub; public Bathroom(){ this.tub = new Tub(); } public void runBath(){ tub.Fill(); } } Interfaces • Inheritance allows us to define common classes in terms of superclass. i.e. A Car is a type of Vehicle. • Sometimes though we may want to possibly expose a set of methods across unrelated classes that say what an object can do. • An interface in C#, allows us to achieve this. An interface essentially says here is a contract that I am exposing, but I am providing no implementation. If you implement this contract, then you have to provide your own implementation for this contract. Interfaces (continued) • Lets take an analogy, imagine that you are a Teacher. However also as part of your role, you are also the First Aid Officer. A Teacher doesn’t necessarily have to be a First Aid officer but can choose to be one. An accountant in another company, may choose to be a First Aid Officer also. • In this scenario, we could define an interface called IFirstAidOfficer, that would expose methods that all First Aid officers are expected to do. Therefore both the Teacher and Accountant classes could implement the IFirstAidOfficer interface and provide their own implementations. Interfaces in C# • An interface does not have any implementation for the methods it defines, it delegates that to the classes that implement it. • Declaring an interface. We typically name an interface with a capital I prefix: public interface IFirstAidOfficer{ void performCPR(); } • Implementing an interface: public class FighterPilot : Pilot, IFirstAidOfficer{…} This class FighterPilot inherits from Pilot and implements IFirstAidOfficer. Interfaces in C# (continued) public class FighterPilot : Pilot, IFirstAidOfficer{ … //Pilot Methods below … //Implementing IFirstAidOfficer public void performCPR(){ tiltHead(); startCompressions(); } } Extra Collections • A List is a very useful collection that allows us to add, remove and retrieve items in a certain order. • However sometimes a list may not be the best possible implementation for certain scenarios. • We are going to look at a few key extra collections that can be used to mimic different functionality you require in your program. • These extra collections are called: • • • Dictionary Queue Stack Dictionary • Think of an Oxford English dictionary, it contains a list of words along the left hand side of the page alongside with their corresponding definition. • In programming, we also have a special type of collection called a Dictionary that also allows us to create a list of key-value pairs. This means that we can specify a key, that is to be associated with certain data – i.e. the value. • Dictionaries are useful for quickly looking up a piece of data. Dictionary (continued) • In C#, we declare a dictionary as follows: Dictionary<TKey, TValue> kv = new Dictionary<TKey, TValue>(); • TKey, and TValue should be replaced by the types that you want your key and values to be. i.e. int, string etc. • Dictionaries are very versatile, the key and value type can be pretty much any type as long as the key is suitable for easy lookup and the value type is what you want to store. Dictionary (continued) Dictionary<String, Account> accountDict = new Dictionary<String, Account>(); • So here we are creating a dictionary with a key of type String which might be the account holder’s name, and a value of type Account which is a class. • To add items to a dictionary we use the Add method along with the key we want to use and the value we want to associate with this key. accountDict.Add("Sean", new Account("Savings", 0.00)); accountDict.Add("Brian", new Account("Interest", 0.00)); Dictionary (continued) • To retrieve the value at a certain key we use: Account account = accountDict[“Sean”]; • To remove a item from a dictionary we specify the item via it’s key: accountDict.Remove(“Brian”); • To check if a certain key exists (true or false) we use: bool keyExists = accountDict.ContainsKey(“John”); • To retrieve all the keys in the dictionary as an array we use: List<string> allKeys = new List<string>(accountDict.Keys); Queue • We encounter queues in every day life. For example we queue up at shopping markets to pay for our items. • In Computer Science, a Queue is another type of collection that has some special properties. • When we think of a queue at a shopping centre, we may arrive at a till, and there may be either some customers there or no customers. Queue (continued) • If there are some customers there we will join the back of the queue. Or if there are no customers there we will immediately get our items served. • Sometimes we want to mimic a queue in programming, so that items can only be accessed in a certain order. • A queue is known as a First In First Out data structure. Whoever is at the top of the queue will be processed next. • In C#, we have a Queue collection that mimics this functionality so that items can be processed in a First In First Out (FIFO) order. Queues in C# • Creating a queue in C# where T can be any type. Queue<T> queue = new Queue<T>(); Queue<Customer> customerQueue = new Queue<Customer>(); • To add an item to the back of a queue, we enqueue the item queue.Enqueue(new Customer(“John”)); • To remove an item from the front of a queue, we dequeue the item Customer nextCustomer = queue.Dequeue(); • To check what is at the front or top of the queue, we can use the method peek Customer checkWhoIsNext = customerQueue.Peek(); Stacks • A Stack is another special type of collection that allows you to access data in a certain order. • A good example of a stack is a stack of plates. When we add a plate to the stack, it becomes the top plate on the stack. So if we were to be remove a plate from the stack, we can only remove the plate at the top of the stack, i.e. the one we most recently added. • This means that a Stack is a Last In First Out (LIFO) data structure. I.e. the first item we get out is the last item that we have added. • In C#, we have a Stack collection that mimics this functionality so that items can be processed in a Last In First Out (LIFO) order. Stacks in C# • Creating a Stack in C# Stack<T> stackName = new Stack<T>(); Stack<Plate> plates = new Stack<Plate>(); • Adding to a Stack is called pushing plates.Push(new Plate()); • Removing the top item from a stack is called popping Plate plate = plates.Pop(); • We can also check what is at the top of the stack by peeking Plate plate = plates.Peek(); • We can empty a stack by clearing plates.Clear(); Covariance • Covariance is the act of up-casting an entire list at once to a more general list. • For example, if you had a list of Ducks (which are a subclass of a Bird), and you wanted to up-cast the entire list to a list of Birds, you would do the following: • So we could take a llist of ducks, and assign it to a IEnumerable<Bird> interface. Then we can add these upcasted ducks to a list of bird objects. • An IEnumerable is just an interface that defines generic enumerator (iteration) methods. Covariance Example //create list of ducks List<Duck> ducks = new List<Duck>(); //upcast entire list to IEnumerable Bird IEnumerable<Bird> upcastDucks = ducks; List<Bird> birds = new List<Bird>(); //add our upcasted ducks to the bird list birds.AddRange(upcastDucks); Sorting with IComparable<T> • We may want the ability to tell a list how to sort a class that we have created. • To sort a list, we can call the List.Sort() method. This method will sort any type of class that implements the IComparable<T> interface. • The IComparable<T> interface has one method CompareTo(<T>). • So assuming we have a list of Duck objects, and we wanted the ability to compare all of our Duck objects by their size. Our Duck class would implement the IComparable<Duck> interface and we would provide our implementation on what criteria we want our ducks to be sorted against. Sorting with IComparable<T> • CompareTo() returns a 1 if the current duck is bigger than the duck we are comparing against. If it returns a -1, if the current duck is smaller than the duck we are comparing against otherwise it returns a 0 to indicate they are the same size. • Now we can call ducks.Sort() and they will be sorted based on their size. IComparer<T> interface • We may want to create multiple ways in which we can sort our ducks. So at runtime, we can pass in what way we want to sort the ducks. • To do this we can create a Comparer class that implements the IComparer<T> interface. • Then when we are calling the List.Sort() method, we can pass our comparer class in as a parameter. //assume we have a list of ducks CompareDucksBySize comparer = new CompareDucksBySize(); ducks.Sort(comparer); printDucks(ducks); CompareDucksBySize class class CompareDucksBySize : IComparer<Duck>{ public int Compare(Duck x, Duck y){ //if Duck x is smaller than Duck Y return -1 if(x.Size < y.Size){ return - 1; } //if Duck x is bigger than Duck Y return 1 if(x.Size > y.Size){ return 1; } //If they are the same size return 0 return 0; } } Object ToString() • All objects in C# automatically inherit from the Object class. The object class provides a few methods that can be overridden by any subclass of Object. • One of the most useful methods exposed is the ToString() method. ToString() returns a string representation of an object. • This can be useful, as in our classes we can override the ToString() method from the object class, to provide our own string representation of each of our objects. Object ToString() (continued) • By default, the ToString() method just returns the name of the class. • In a Car class, we could override ToString() so that we could instead return the type and year of the car when toString() is invoked on a Car object. public class Car{ private string nameOfCar; private int year; … //Overriding ToString() public override string ToString(){ return nameOfCar + " " + year; } } Overloading Methods • Overloading allows you to create multiple methods with the same name in the same scope however they differ in their method signatures. public void Add(int number1, int number2) public void Add(int number1, int number2, int number3) public void Add(int number1, int number2, int number3, int number4) Overloading Constructors • We can also overload constructors for an object, so that perhaps you can have different ways of constructing the object with different defaults. public Student(int studentNumber) public Student(int studentNumber, String studentName) public Student(int studentNumber, String studentName, double bursaryBalance) Reading Head First C# • • • • Build a House Exercise: pages 332 - 346 Random Cards Exercise: page 375 - 379 Birds List Exercise: pages 379 - 380 Move Cards Exercise: pages 382 - 386 What’s to come next time • Week 12 • • • This and That in C# Abstract classes Form Components • • • • Menus Navigation Toolbars Buttons