When you think of object orientation, you might think of three characteristics of object orientation: encapsulation, inheritance, and polymorphism.
reference
- The beauty of software design
encapsulation
- Put closely related information together to form a basic unit.
- The basic units are combined one by one, and the larger units are gradually built up layer by layer.
When we design a class, we first consider what behavior its objects should provide. We then provide methods based on these behaviors, and finally consider what fields to use to implement these methods.
In reality, we tend to program procedurally. For example, in the earliest design idea of DBFirst, we first design the tables of the database, which fields are in the table, use ORM to generate entities, and assign values to the fields of each entity object. Second, we do business logic operations at the BLL or Service layer. This is basically a departure from object-oriented encapsulation.
The focus of encapsulation is on what behavior the object provides, not what data it has. That is, even if we think of objects as data plus functions, data and functions are not equal. Functions are interfaces, data are internal implementations, and as we’ve always said, interfaces are stable, implementations are mutable.
C# 9.0 provides a new type: records
record RecordPerson { public string Name { get; init; } public int Age { get; init; }}Copy the code
For a Record object, its properties can only be initialized, not modified. When an object is exposed to too much detail, it becomes unstable. As requirements change, if a business process is changing the Age attribute of an object everywhere, the probability of bugs becoming more and more high and difficult to detect.
For an object, encapsulation lies in what behavior we provide, not in getters and setters, which are fields or properties that expose the inner details.
Many teams add interfaces to their systems very casually, with hundreds or thousands of interfaces in a seemingly uncomplicated system.
If you try to change the system and remove some of the interfaces, it’s likely to cause an online failure because you never know which team is using it and when. So, in software design, you need to be very careful about exposing interfaces. Minimize interface exposure. That is, every time you add an interface, you need to find a good reason.
inheritance
When I was in college and at work, the first thing I understood about object orientation was that one object inherited another, and that was object orientation. For example, teachers and students, if we abstract a Person class, they both have a Name, an Age, and implement an Introduction interface in Person, then my teachers and students can reuse this method.
Demo
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void Introduction()
{
Console.WriteLine($"I am {Name}, Age:{Age}!"); }}public class Student : Person {}
public class Teacher : Person{}
Copy the code
This is not a problem in C# or Java syntax, but is it really the right posture for inheritance?
Composition over Inheritance
If a solution can be implemented by composition or inheritance, choose composition.
In C#, Java is a single inheritance language design, each class can only have one parent class, once inheritance is occupied by implementation inheritance, interface inheritance will be very troublesome. That said, implementing inheritance as a way to reuse code is not something that should be encouraged.
In summary: Composition is superior to inheritance, and inheritance is for polymorphism, not reuse.
polymorphism
One interface, many forms
Java polymorphism implementation
interface Shape {
// Drawing interface
void draw(a);
}
class Square implements Shape {
void draw(a) {
// Draw a square}}class Circle implements Shape {
void draw(a) {
// Draw a circle}}Copy the code
Go polymorphism implementation
type Shape interface {
draw()
}
type Square struct{}func (s Square) draw(a) {
// Draw a square
}
type Circle struct{}func (c Circle) draw(a) {
// Draw a circle
}
Copy the code
Understand polymorphism, but also understand interfaces. It separates the parts that change from the parts that don’t change, creating a boundary between the two. An important programming principle, which underlies many design principles, is programming to interfaces.