Object-oriented programming (OOP)
Table of Contents
The most commonly recognized set of OOP concepts or principles is often referred to as the SOLID principles. SOLID is an acronym that stands for:
-
Single Responsibility Principle (SRP): A class should have only one reason to change, meaning it should have a single responsibility or purpose.
-
Open-Closed Principle (OCP): Software entities (classes, modules, functions) should be open for extension but closed for modification. In other words, you should be able to add new functionality without modifying existing code.
-
Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types without affecting the correctness of the program. In simpler terms, objects of a superclass should be able to be replaced by objects of its subclasses without causing issues.
-
Interface Segregation Principle (ISP): Clients should not be forced to depend on interfaces they do not use. This principle emphasizes the importance of creating small, specific interfaces for different clients rather than having large, general-purpose interfaces.
-
Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules; both should depend on abstractions. This principle encourages the use of abstractions (interfaces or abstract classes) to decouple classes and promote flexible, interchangeable components.
These principles were first introduced by Robert C. Martin ("Uncle Bob") and have become widely accepted guidelines for designing maintainable, scalable, and robust object-oriented systems. Adhering to these principles can lead to code that is easier to understand, test, and maintain, and that exhibits better modularity and extensibility.
Single Responsibility Principle

polymorphism
In JavaScript, the switch statement is not an example of polymorphism. Polymorphism typically refers to the ability of objects of different types to be treated as instances of a common superclass or interface, allowing for substitutability and dynamic method dispatch. The switch statement, on the other hand, is a control flow construct used for branching based on the value of an expression.
Polymorphism in React Native and Node.js can be achieved through the use of inheritance and interfaces. Here are some common code blocks that demonstrate polymorphism in these contexts:
-
Polymorphism in React Native: In React Native, component-based development is prevalent. Polymorphism can be achieved by creating a base component that defines common behavior and then extending it to create specialized components. Here's an example:
// Base Component
class Shape extends React.Component {
render() {
return <View>{this.renderShape()}</View>;
}
renderShape() {
// Common shape rendering logic
}
}
// Specialized Components
class Circle extends Shape {
renderShape() {
// Circle-specific rendering logic
}
}
class Square extends Shape {
renderShape() {
// Square-specific rendering logic
}
}
// Usage
<Circle /> // Renders a circle shape
<Square /> // Renders a square shape
```
In this example, the `Shape` component serves as the base class, and the `Circle` and `Square` components inherit from it. Each specialized component overrides the `renderShape()` method to provide its own rendering logic while leveraging the common behavior defined in the base class. -
Polymorphism in Node.js: In Node.js, polymorphism can be achieved by defining interfaces or abstract classes and implementing them in multiple concrete classes. Here's an example:
// Interface
class Shape {
draw() {
throw new Error('Method not implemented');
}
}
// Concrete Classes
class Circle extends Shape {
draw() {
console.log('Drawing a circle');
}
}
class Square extends Shape {
draw() {
console.log('Drawing a square');
}
}
// Usage
function drawShape(shape) {
shape.draw();
}
const circle = new Circle();
const square = new Square();
drawShape(circle); // Draws a circle
drawShape(square); // Draws a square
```
In this example, the `Shape` class defines an interface with a `draw()` method. The `Circle` and `Square` classes implement this interface by providing their own `draw()` implementations. The `drawShape()` function accepts any object that adheres to the `Shape` interface and invokes the `draw()` method, allowing polymorphic behavior when drawing different shapes.
These examples demonstrate how polymorphism can be achieved in React Native and Node.js by leveraging inheritance, interfaces, and method overriding. By designing code with polymorphism in mind, you can write more flexible and extensible applications.
Access Modifiers
Virtual
- derived class function
Override
Public
The type or member can be accessed by any other code in the same assembly or another assembly that references it.
Private
The type or member can only be accessed by code in the same class or struct.
protected
The type or member can only be accessed by code in the same class or struct, or in a derived class.
internal
The type or member can be accessed by any code in the same assembly, but not from another assembly.
protected internal
The type or member can be accessed by any code in the same assembly, or by any derived class in another assembly.
When no access modifier is set, a default access modifier is used. So there is always some form of access modifier even if it's not set.
sealed
- derived classes can't override the method
partial
- override default Insert, Update, Delete methods
- partial classes
- partial methods
Static
The static modifier on a class means that the class cannot be instantiated, and that all of its members are static. A static member has one version regardless of how many instances of its enclosing type are created.
Other Types
- declared directly within a namespace can be declared as public or internal
- interfaces default to internal access just like classes and structs
- Interface members are always public because the purpose of an interface is to enable other types to access a class or struct
- No access modifiers can be applied to interface members.