App Develop Week 9

Recap

(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 w/ Abstraction V.S. Programming To Abstraction

“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.

Programming with Abstraction

  • 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!");
}
}

Programming to Abstraction

  • 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.

DRY — Don’t Repeat Yourself

//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 Coding Principles

Solid stands for…

Single responsibility (modularity)

Open/closed principle

Liskov substitution principle

Interface segregation

Dependency inversion

Single Responsibility (Modularity)

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.

  1. Put things into methods.

  2. 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.

Open/Closed Principle

Liskov Substitution Principle

Interface Segregation

Dependency Inversion

robot