You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
6.2 KiB
Markdown
271 lines
6.2 KiB
Markdown
# Interfaces
|
|
|
|

|
|
|
|
---
|
|
|
|
# Overview
|
|
|
|
Interfaces
|
|
|
|
Interfaces or Inheritance?
|
|
|
|
# Interfaces
|
|
|
|
* In addition to abstract classes, __interfaces __ are a way to achieve abstraction to your program
|
|
* Interfaces are classes that have __no internal functionality__
|
|
* Interfaces describe the methods and properties that a class has to have when implementing the interface
|
|
* Think of it as a _contract_ : by __implementing __ an interface, the class _has to_ _use _ all the methods and properties that are defined in the interface
|
|
* As with abstract classes, interfaces cannot be instantiated directly
|
|
* It wouldn't make any sense as interfaces have no implementation
|
|
* Interfaces are way more commonly used than abstract classes
|
|
|
|
# Creating an Interface
|
|
|
|
* Define an interface using the interface keyword instead of class:
|
|
* interface IUser
|
|
* {
|
|
* int Id { get; set; }
|
|
* string Name { get; set; }
|
|
* void GetUserStatistics();
|
|
* }
|
|
* Interface names should begin with the capital I letter to more easily identify them as interfaces and not classes
|
|
* Notice that interfaces can contain both properties and methods but not fields
|
|
* Methods are declared without the method body (no implementation)
|
|
* The methods are implemented on the classes that uses the interface
|
|
|
|
# Implementing an Interface
|
|
|
|
Implement an interface just like you would inherit a class:
|
|
|
|
class User : IUser
|
|
|
|
{
|
|
|
|
}
|
|
|
|
The compiler will now throw a bunch of errors saying that the User class does not implement the properties and methods defined in the interface
|
|
|
|
Let's fix that by defining those now
|
|
|
|
# Implementing an Interface (continued)
|
|
|
|
class User : IUser
|
|
|
|
{
|
|
|
|
public int Id { get; set; }
|
|
|
|
public string Name { get; set; }
|
|
|
|
public void GetUserStatistics()
|
|
|
|
{
|
|
|
|
// Some code here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
The interface is now fully implemented and the compiler is happy
|
|
|
|
The interface do not dictate _how_ the methods are implemented, those just need to be implemented.
|
|
|
|
❕
|
|
|
|
To quickly implement the interface, click the IUser interface name and click the light bulb -> implement interface.
|
|
|
|
# Implementing Multiple Interfaces
|
|
|
|
* Unlike with inheritance, classes can implement multiple interfaces
|
|
* In contrast, classes can only inherit from one base class
|
|
* This is done by separating the interfaces with a comma:
|
|
* class Rock : IPickable, IThrowable, ICrushable
|
|
* {
|
|
* // Code that implements IPickable, IThrowable and ICrushable
|
|
* }
|
|
|
|
# Why Use Interfaces?
|
|
|
|
Interfaces allow common functionality among classes that are otherwise unrelated to each other
|
|
|
|
In those cases, inheriting from some shared base class wouldn't make sense
|
|
|
|
Consider the following example:
|
|
|
|
public void DeleteData(IDeletable data)
|
|
|
|
{
|
|
|
|
data.Delete();
|
|
|
|
}
|
|
|
|
The above method accepts _any _ type of object that implements IDeletable, regardless of other functionality
|
|
|
|
# Interface or Inheritance?
|
|
|
|
| class Dog |
|
|
| :-: |
|
|
| -Eat()-Sleep()-WagTail() |
|
|
|
|
| class Human |
|
|
| :-: |
|
|
| -Eat()-Sleep()-Contemplate() |
|
|
|
|
| class Bear |
|
|
| :-: |
|
|
| -Eat()-Sleep()-Hibernate() |
|
|
|
|
All classes could inherit from a base class Animal, which has methods Eat() and Sleep()
|
|
|
|
Should the base class be abstract? Depends on your program: do you ever need an object that can only Eat() and Sleep()?
|
|
|
|
| class Tree |
|
|
| :-: |
|
|
| -Grow()-Photosynthesize() |
|
|
|
|
| class Human |
|
|
| :-: |
|
|
| -Grow()-Move() |
|
|
|
|
| class Car |
|
|
| :-: |
|
|
| -Move()-Explode() |
|
|
|
|
It wouldn't make sense to use inheritance here, since there is no functionality that is shared between all classes
|
|
|
|
Instead you could make two interfaces: IGrowable and IMovable
|
|
|
|
# Interfaces - Example
|
|
|
|
Let's make a program that has two lists: one for all objects that can move (IMovable) and one for all objects that can be carried (ICarryable)
|
|
|
|
Finally every movable object is moved and carryable object is carried
|
|
|
|
interface IMovable
|
|
|
|
{
|
|
|
|
void Move();
|
|
|
|
}
|
|
|
|
interface ICarryable
|
|
|
|
{
|
|
|
|
void Carry();
|
|
|
|
}
|
|
|
|
class Elephant : IMovable
|
|
|
|
{
|
|
|
|
public void Move()
|
|
|
|
{
|
|
|
|
Console.WriteLine("The elephant is moving'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Cat : IMovable, ICarryable
|
|
|
|
{
|
|
|
|
public void Move()
|
|
|
|
{
|
|
|
|
Console.WriteLine("The cat is moving'");
|
|
|
|
}
|
|
|
|
public void Carry()
|
|
|
|
{
|
|
|
|
Console.WriteLine("You are carrying the cat");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Rock : ICarryable
|
|
|
|
{
|
|
|
|
public void Carry()
|
|
|
|
{
|
|
|
|
Console.WriteLine("You are carrying the rock");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Program
|
|
|
|
{
|
|
|
|
static void Main(string[] args)
|
|
|
|
{
|
|
|
|
Elephant elephant = new Elephant();
|
|
|
|
Cat cat = new Cat();
|
|
|
|
Rock rock = new Rock();
|
|
|
|
List<IMovable> movables = new List<IMovable>{ elephant, cat };
|
|
|
|
List<ICarryable> carryables = new List<ICarryable>{ cat, rock };
|
|
|
|
foreach (IMovable movable in movables)
|
|
|
|
movable.Move();
|
|
|
|
foreach (ICarryable carryable in carryables)
|
|
|
|
carryable.Carry();
|
|
|
|
}
|
|
|
|
}
|
|
|
|

|
|
|
|
# Exercise 1: A Web of Relations
|
|
|
|
Create a console application that has an interface IInfo, and two classes Product and Category, which both implement IInfo.
|
|
|
|
Inside IInfo, declare a property InfoText and a method PrintInfo
|
|
|
|
Implement the property and method in Product and Category
|
|
|
|
Initialize a couple of products and categories, with info texts of your choice
|
|
|
|
Create a list of type IInfo, and add the products and categories to it
|
|
|
|
Create a main loop, where each time the user presses enter, all the info texts inside the list are printed
|
|
|
|
# Exercise 2: The IComparable Interface
|
|
|
|
Create a program that sorts a list of shapes by area, using the [IComparable](https://docs.microsoft.com/en-us/dotnet/api/system.collections.icomparer?view=netcore-3.1) interface, which is used by the List.Sort() method to know whether the elements should come before or after each other in the list.
|
|
|
|
Start by creating 4 classes: __Shape__ , __Square__ , __Triangle__ and __Circle__ . Square, Triangle and Circle inherit from Shape. Shape implements the __IComparable\<Shape>__ __ __ interface.
|
|
|
|
Shape has a public property double Area. Square, Triangle and Circle have to have constructors to calculate the area: Square and Triangle with length and height, and Circle with radius.
|
|
|
|
The CompareTo(Shape? other) method should return 1 if the area is greater than what is being compared with (Shape other), 0 if the areas are equal, and -1 if the area is smaller.
|
|
|
|
Try out your solution by creating a couple of squares, triangles and circles in a list of shapes, and sorting the list with the .Sort() method. Print the areas in the sorted array with a foreach loop. They should be printed in an increasing order.
|
|
|