(1) Polymorphism
static void xyz(class X){
//code goes here
}
If a method takes in a class, it not only takes in objects of that class, but children of the class also.
The keyword “sealed” means that a class has no child classes.
Therefore, polymorphism is important because it means that…
If a method takes in an interface, it can also implement …
(2) Abstract Classes
Non-concrete methods —>
Concentre methods —>
(3) Interfaces
Only have non-concrete methods
“Programming with abstraction” and “programming to abstraction” means 2 different things.
In simple terms, the key difference is:
Programming with abstraction focuses on using abstraction techniques.
Programming to abstraction means designing code to depend on abstractions, not concrete implementations.
Refers to using abstraction as a tool in programming.
Involves designing and writing code using abstract concepts like interfaces, abstract classes, and encapsulation to hide implementation details.
Example: Using functions, classes, or modules to abstract complex logic so that the code is more maintainable and readable.
abstract class Animal {
public abstract void MakeSound();
}
class Dog : Animal {
public override void MakeSound() {
Console.WriteLine("Bark!");
}
}
Means writing code that depends on abstractions rather than concrete implementations.
Encourages dependency on interfaces or abstract classes instead of specific classes, which improves flexibility and scalability.
Example: Instead of depending on a concrete MySQLDatabase
class, depending on a Database
interface allows switching to a different database implementation easily.
interface IDatabase {
void Connect();
}
class MySQLDatabase : IDatabase {
public void Connect() {
Console.WriteLine("Connected to MySQL");
}
}
class DataService {
private IDatabase _database;
public DataService(IDatabase database) {
_database = database;
}
public void GetData() {
_database.Connect();
Console.WriteLine("Fetching data...");
}
}
In this example, DataService
depends on IDatabase
, not MySQLDatabase
, making it easier to switch database implementations.
//This code is about DRY - don't repeat yourself
using System;
{
namespace Week9_Lec1_Inheritance01
{
class Program
{
internal class Employee
{
private string name;
private string DOB;
}
}
}
}
/*Why isn't this programming design?
Although the code uses encapsulation -- which is one of the criteria for good programming design -- but it doesn't follow DRY and doesn't code reuse. It would be better as follows: */
using System;
{
namespace Week9_Lec1_Inheritance02
{
class Person
private string name;
private string DOB;
{
internal class Student: Person
{
private double GPA;
//By default classes are private, but on test prof would like us to specify whether a class is public or private by clearly using the 'private' keyword
}
internal class Employee: Person
{
private double salary;
}
internal class Athlete: Person
{
string favSport;
}
}
}
}
Solid stands for…
Single responsibility (modularity)
Open/closed principle
Liskov substitution principle
Interface segregation
Dependency inversion
Each module should have one job.
Each class should have one job.
A god class is a class that contains all of the code in your program.
We avoid using god classes because they lead to highly/tightly coupled…
To avoid use of god classes —> modularize your code.
Put things into methods.
Put things into classes.
//This sample code violates single responsibility criteria
using System;
namespace Week9_Lec1_SOLID_SingleResponsibility_Violated
internal class Modem
{
public void DialUp() { }
public void Send() { }
public void HangUp() { }
public void Receive() { }
}
//This sample code DOES NOT violate single responsibility criteria
/* This version of the code seen in the previous example uses significantly better standard of programming because the code is modular.
In example 1, the methods had high coupling, had low cohesion. So if an error were to occur in one methods -- it could affect the rest of the methods.
However, in this example, the method there is low coupling & high cohesion. If an error was to occur in the chanel class, it would not affect the connection class. */
using System;
namespace Week9_Lec1_SOLID_SingleResponsibility_NOTviolated
{
class Channel
{
public void Send() { }
public void Receive() { }
}
class Connection
{
public void DialUp() { }
public void HangUp() { }
}
}
public class Circle{
private int radius;
}
Circle(int radius){
this.radius = radius;
} //You know this is a constructor bc the method name is the same as the class name
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
public class CalculateArea {
double calculateArea(Circle c){
//provide the code to calculate the area of a circle
}
}
double printArea (double area) {
//proive the code to print out area
}
//What's wrong with the class CalculateArea?
/* the 2 methods in CalculateArea are doing 2 different jobs, which violates SOLID's rules. the class CalculateArea should only have one purpose -- to calculate are of the circle. One way to solve this would be to create another class called "printArea" that includes a method solely dedicated to printing the area of the circle.