Classes and Objects
I. Object-Oriented and Process-Oriented
Object-Oriented Programming (OOP) and Procedure-Oriented Programming (POP) are two different programming paradigms, which have significant differences in programming ideas, features, advantages and application scenarios.
1、Programming ideas
- process-oriented: It is a process-centered programming idea that focuses on the steps of solving a problem, i.e., first analyze the steps needed to solve the problem, and then use functions to implement these steps step by step, and call them one by one sequentially when using them.
- object-oriented: It is a class of programming language that uses objects as the basic program structure unit. Object-oriented to the composition of the problem matters decomposed into individual objects, through the different objects between the invocation and mutual collaboration to solve the problem.
2. Characteristics
-
process-oriented
:
- Good for solving simple problems that don't require much collaboration or abstraction.
- Focus on the steps to solving the problem rather than the nature of the problem.
- Low code reusability, poor scalability, not easy to maintain.
- Only encapsulation, no inheritance or polymorphism.
-
object-oriented
:
- Suitable for solving complex problems that require collaboration and abstraction from multiple parties.
- Focus on the nature of the problem.
- Code reusability is high, scalable and easy to maintain.
- With encapsulation, inheritance, polymorphism three major characteristics.
3. Advantages
-
process-oriented
:
- Performance is better because class calls require instantiation, which has more overhead and is more resource intensive.
- In some specific areas (e.g. microcontrollers, embedded development, Linux/Unix system programming, etc.), performance is the most important factor, so process-oriented is more applicable.
-
object-oriented
:
- easy maintenance: Because object-oriented has encapsulation, inheritance, and polymorphism, it is possible to design low-coupling systems that are more flexible and easier to maintain.
- reusable: Through inheritance and polymorphism, programmers can achieve code reuse and extension to improve development efficiency.
- easily extensible: Object-oriented design allows the system to adapt to changes more easily, adding new features or modifying existing ones with less impact on the rest of the system.
4、Application Scenario
- process-oriented: It is more suitable for solving simple, straightforward problems, or for use in scenarios where performance is critical.
- object-oriented: It excels in complex scenarios such as large software systems, graphical user interface (GUI) applications, and game development. With the hierarchical structure of classes and objects, programmers can divide complex systems into multiple independent modules, improving code maintainability and scalability.
To summarize, object-oriented and process-oriented each have their own advantages and applicable scenarios. When choosing a programming paradigm, comprehensive consideration should be made based on factors such as the complexity of the specific problem, performance requirements, and the familiarity of the development team.
II. Concepts of classes and objects
1. The concept of class
A class is a blueprint or template for defining objects in object-oriented programming (OOP). It describes an abstract representation of a set of objects with the same properties and behavior. Classes define the state (through properties or member variables) and behavior (through methods) of an object. In programming languages, a class is a data type, but it is a composite type because it can contain multiple properties and methods.
2. The concept of an object
An object (Object) is an instance of a class. When you use a class to create an entity, you create an object. Each object has properties and methods defined in the class, but their property values can be different depending on the values specified when the object was created. Objects represent real-world entities or concepts such as people, cars, houses, etc.
3. Member variables
Member variables (also known as attributes) are variables defined in a class to store information about the state of an object. Member variables can be of any legal data type, including basic data types (e.g., int, float) and reference data types (e.g., arrays, objects of other classes). Member variables can be private, protected, or public, which determines the scope of their access.
4. Member methods
A member method (also known as a function or procedure) is a block of code defined in a class to perform an operation or return a result. Methods define the behavior that an object can perform. Similar to member variables, methods can have access modifiers (private, protected, public) that control their access. Methods can take parameters and have return values.
5. Instantiation of objects
Instantiation of an object is the process of creating an object using a class. In Java, this is usually done using thenew
keyword completion, followed by the name of the class and the constructor (and, if necessary, the parameters passed to the constructor).
In Java, object instantiation (also known as creating an object) is a core concept in object-oriented programming, which refers to the process of creating instances (i.e., objects) of a class based on the definition of the class.There are several main ways to instantiate an object:
1. Utilizationnew
Keywords.
This is the most common way to instantiate an object. Instantiating an object through thenew
keyword calls the class's constructor (constructor function) to create the object. If the constructor is not explicitly defined in the class, the compiler automatically generates a default unparameterized constructor. Example:
MyClass obj = new MyClass();
A parametric constructor (also known as a constructor with parameters) is used when instantiating an object. The main responsibility of a constructor is to initialize the state of an object while creating it. When you use a parametric constructor, you need to provide the necessary parameters while creating the object, which are passed to the constructor and used to initialize the state of the object.
The following is a simple example showing how to instantiate an object in Java using a parametric constructor:
public class Person {
private String name;
private int age;
// parametric constructor
public Person(String name, int age) {
= name;
= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Main {
public static void main(String[] args) {
// 使用parametric constructor实例化 Person boyfriend
Person person = new Person("Alice", 30);
// exports Alice
(());
// exports 30
(());
}
}
In this example, thePerson
Classes have two private propertiesname
cap (a poem)age
, and has a constructor that accepts both properties as arguments. When we create thePerson
When passing an instance of the class"Alice"
cap (a poem)30
These two values are given to the constructor and these values are used to initialize thename
respond in singingage
Properties.
The benefits of using a parametric constructor include:
- Initialize the object state: You can set the initial state of an object while creating it.
- clear code: Specifies the initial information required when the object is created.
- mandatory parameter passing: If the required parameters are not supplied, the compiler will not allow the object to be created, thus reducing the likelihood of errors.
To summarize, a parametric constructor is used when an object is created to initialize the object's state and ensure that the object has been properly set to its initial values before it is used.
2. Factory model
Factory Pattern is a creation-based design pattern that provides an optimal way to create objects. In factory pattern, we create a factory class to encapsulate the logic of instantiating an object. The client gets the object instance by calling the methods of the factory class without having to go directly through thenew
keyword to create objects. The factory pattern realizes the separation of the creator and the caller and helps decouple the system. Example:
public class MyClassFactory {
public static MyClass getInstance() {
return new MyClass();
}
}
MyClass obj = ();
3. Reflections
The Java reflection mechanism allows programs to dynamically create objects and access their properties and methods at runtime. This is accomplished through themaybe
class
newInstance()
method that creates instances of an object at runtime. This approach is more flexible, but less efficient and tends to break encapsulation. Example:
Class<? > clazz = ("");
MyClass obj = (MyClass) ();
// Or use Constructor
Constructor<MyClass> constructor = ();
MyClass obj2 = ();
4. clone()
methodologies
If the class implements theCloneable
interface and rewrites theclone()
method, then it is possible to call an existing object'sclone()
method to create a new object instance. This method creates a new object by copying the values of the properties of an already existing object, but it should be noted that this method creates a shallow copy, and if the object contains reference-type properties, these reference-type properties still point to the values of the properties in the original object. For example:
public class MyCloneableClass implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return ();
}
}
MyCloneableClass original = new MyCloneableClass();
MyCloneableClass copy = (MyCloneableClass) ();
Note: Cloning
(1) What to use cloning?
If you want to make a copy of an object, but want to keep the original object for the next operation, you need to clone it.
(2) How to realize object cloning?
Implement the Cloneable interface, override the clone method.
Serializable interface , through the serialization and deserialization of objects to achieve cloning , you can achieve a really deep cloning . BeanUtils, apache and Spring provide bean tools, but this is a shallow cloning.
(3) What is the difference between deep copy and shallow copy?
Shallow copy: only basic type variables are cloned, not reference type variables.
Deep cloning: cloning of both basic type variables and reference type variables.
5. Serialization and deserialization
Java's serialization mechanism allows the state of an object to be saved to a byte stream and the state of the object can be restored from the byte stream. Objects are saved to a file or transferred over a network through serialization and then restored from the file or network through deserialization when needed. This approach can be used for deep copies of objects and persistent storage of objects. Example:
// serialize
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(""));
(obj);
();
// 反serialize
ObjectInputStream in = new ObjectInputStream(new FileInputStream(""));
MyClass objCopy = (MyClass) ();
Note that the class to be serialized must implement theSerializable
interface, and if the class contains other objects that need to be serialized as properties, then those objects must also implement theSerializable
Interface.
In summary, there are various ways to instantiate objects in Java, each of which has its own applicable scenarios and advantages and disadvantages. In actual development, you should choose the appropriate way according to the specific needs.
Memory Model and Object Creation
Memory is divided into stack memory, which holds references to variables of basic data types and reference types, and heap memory, which holds object instances.
2. When the object is created, the instantiated object is placed in the Java heap and the contained member variables and static variables are stored in different memory areas according to their types.
In Java, object creation and memory allocation involves several key memory areas. The following are the locations where member and static variables are stored when an object is created:
-
Java Heap:
- The Java heap is the area of the Java Virtual Machine (JVM) used to store object instances. The heap is used for storing object instances when they are passed through the
new
keyword creates an object, instances of the object (including member variables and methods) are allocated in heap memory. - Heap memory is an area shared by all threads, which is managed by the Garbage Collector (GC), which is responsible for the life cycle of an object, including creation and destruction.
- The Java heap is the area of the Java Virtual Machine (JVM) used to store object instances. The heap is used for storing object instances when they are passed through the
-
member variable:
- Non-static member variables (instance variables) are associated with a specific object instance, and they are stored in the Java heap with the object instance.
- Each object instance has its own copies of member variables that are allocated in heap memory.
-
static variable:
- Static variables (class variables) are associated with classes, not object instances. They are stored in the Method Area or Metaspace in Jdk8 and later.
- The method area is an area of memory in the JVM used to store the structure of the class, such as the pool of runtime constants, field and method data, and the bytecode contents of constructors and common methods. Static variables are created when the class is loaded and are created only once during the entire life cycle of the Java Virtual Machine.
- Starting with Jdk 8, the method area is replaced by a metaspace. Instead of being part of the virtual machine memory, the metaspace uses local memory (i.e., the operating system's memory) to store class metadata.
-
Methodological area/meta-space:
- The method area or metaspace is a memory area defined in the JVM specification for storing information about classes. The exact implementation of this memory area may vary in different JVM implementations.
- Metaspace is a concept introduced in Jdk 8 that moves class metadata out of JVM memory and stores it in local memory, which reduces JVM memory consumption and improves performance.
-
Java stack:
- When a thread executes a method, a Stack Frame is created to store a stack of local variables and operands. Local variables include parameters in methods and local variables, which are thread-private, and each thread has its own stack.
-
program counter:
- The program counter is a small area of memory used to store a line number indicator for the bytecode currently being executed by the thread. It is thread-private, with each thread having a separate program counter.
To summarize, the non-static member variables of an object are stored in the Java heap, while static variables are stored in the method area or meta space. The design of these memory areas helps the JVM to manage memory and garbage collection efficiently.
3. Reference type variables store the address of the object in the heap, through which the contents of the object can be accessed.
In Java, reference type variables (e.g., instances of classes, arrays, etc.) do not themselves directly store the data of an object; instead, they store references (or pointers) to where the actual data is located. Here are some more details about reference type variables and where they are stored in Java:
-
Heap:
- The actual data of the object (i.e., the state of the object, including all member variables) is stored in the heap. The heap is an area of memory managed by the Java Virtual Machine (JVM) and is primarily used for dynamic memory allocation.
- When you use the
new
When the keyword creates an object, the actual object data is allocated on the heap.
-
Stack:
- Reference type variables themselves are stored on the stack. The stack is used to store local variables, which follow the last-in-first-out (LIFO) principle.
- When you declare a reference type variable in a method, a reference to that variable (not the object itself) is stored on the stack.
Give an example to illustrate the process:
public class MyClass {
private int x;
private String y;
public MyClass(int x, String y) {
= x;
= y;
}
public int getX() {
return x;
}
public String getY() {
return y;
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass(10, "Hello World");
(());
(());
}
}
In this example, theMyClass obj
is a reference variable stored on the stack. When you execute thenew MyClass(10, "Hello World")
When aMyClass
type is created on the heap, and theobj
variable will point to the address of the object on the heap. In this way, when passing theobj
When accessing a method or property of an object, you are actually accessing that object on the heap.
To summarize, in Java, reference type variables themselves are stored on the stack, while the objects they reference are stored on the heap. This separation helps to improve the performance of the program and the efficiency of memory management.
4. Basic data types are stored directly in stack memory and do not require heap memory.
7. Constructors
A constructor is a special method for initializing the state of an object when it is created. Constructors have no return type (includingvoid
), and its name must be identical to the class name.
Default Constructor: If no constructor is explicitly defined in the class, the compiler automatically provides a default constructor with no parameters. However, if at least one constructor (either parameterized or unparameterized) is defined in the class, the compiler will no longer provide a default constructor.
Characterization of the default constructor:
- automatic generation: If no constructor is defined in the class, the compiler automatically generates a default constructor.
- parameterless: The default constructor takes no arguments.
-
access authority: Prior to Java 9, the automatically generated default constructor had package-private access (i.e., default access without any access modifiers). However, starting with Java 9, if the class or its parent (if any) is declared in a module and the class does not explicitly declare a constructor, then the compiler will generate a
protected
access rights to the constructor instead of package private. This change was made to enhance module encapsulation. - Once other constructors are defined, the default constructor is no longer automatically generated: If at least one constructor is defined in the class (with or without parameters), then the compiler will no longer automatically generate a default constructor.
parametric constructor: Can take parameters to initialize the properties of an object when it is created.
constructor overloading: Allows multiple constructors to be defined in a class, as long as they have different argument lists. This allows the appropriate constructor to be chosen to create objects as needed.
8. Use of objects
It mainly involves calling its member methods and accessing its member variables (if they are public). Objects are passed through the dot operator (.
) to access its members.
The basic process of creating and using objects in Java is as follows:
-
create an object
-
declare a variable:
First, you need to declare a variable that will be used to store a reference to the object. The type of the variable should be the type of the class that the object you want to create belongs to.ClassName objectReference; // Assume that ClassName is the class name of the object you want to create.
-
Instantiating Objects:
utilizationnew
keyword to create a new instance of the class and initialize this new object with the class constructor. The constructor is automatically called to initialize the state of the object.objectReference = new ClassName(parameters); // provide parameters as required by the constructor
-
Using Objects
Once an object has been created, its methods can be called or its properties can be accessed through object references.
-
Accessing member variables:
Using the dot operator (.
) to access the object's member variables.; // Assume memberVariable is a member variable in the class.
-
invoke a method:
Similarly, use the dot operator to invoke the methods of an object.(parameters); // Assume methodName is a method in the class
Below is a complete example:
public class Student {
private String name;
private int age;
// constructor with no parameters
public Student() {
}
// parametric constructor
public Student(String name, int age) {
= name;
= age;
}
// methodologies
public void study() {
(name + " is studying.");
}
// getter respond in singing setter methodologies
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
= age;
}
}
public class Main {
public static void main(String[] args) {
// 使用constructor with no parameters创建对象
Student student1 = new Student();
("the fourth child in the family");
(22);
// 使用parametric constructor创建对象
Student student2 = new Student("John Doe", 20);
// 调用methodologies
(); // exports the fourth child in the family is studying.
(); // exports John Doe是 studying.
// Accessing member variables
("Student's name:" + ()); // exports Student's name:the fourth child in the family
("Age of students:" + ()); // exports Age of students:20
}
}
In this example, theStudent
Classes have two constructors: an unparameterized constructor and a parameterized constructor.Main
classmain
method shows how to use these two constructors to create theStudent
object of a class and calls the object's methods as well as accesses its member variables.
9. Destruction of objects
In Java, the destruction of objects relies heavily on the Java Virtual Machine (JVM) built-in Garbage Collection (GC) mechanism. The garbage collector is responsible for automatically detecting and reclaiming the memory space occupied by objects that are no longer used by the program. The following is a detailed description of the Java object destruction mechanism and related practices:
Garbage collection mechanism
Object destruction in Java is accomplished primarily through the garbage collection mechanism. When an object no longer has any references pointing to it, the object becomes a target for garbage collection. The garbage collector automatically reclaims these objects at the appropriate time, freeing up the memory space they occupy. This means that, in general, developers don't need to be concerned about when an object is destroyed because the garbage collection mechanism automatically manages the object's lifecycle.
Manually assisted garbage collection
Although the garbage collection mechanism is automatic, there are some steps that developers can take to aid the garbage collection process in certain situations. For example, when a large object is no longer in use, you can explicitly set its reference to thenull
This helps the garbage collector recognize that the object can be recycled more quickly. It is important to note that calling()
method to request garbage collection is not a good practice, as it can lead to uncertain performance impacts, and modern JVMs are often better able to manage garbage collection timing .
finalize() method
finalize()
The methodology isA protected method in a class that allows some cleanup to be performed before the object is garbage collected. However, using the
finalize()
method is not recommended because its behavior is uncertain and there is no guarantee that it will be executed. In addition, multiple calls to thefinalize()
methods will also not have multiple opportunities to execute . Modern best practices recommend avoiding the use offinalize()
methodology in favor of other resource management techniques such astry-with-resources
statement to ensure that the resource is closed correctly .
Resource management
For external resources that need to be explicitly closed (e.g. files, database connections, etc.), it is recommended to use theAutoCloseable
interface coordinationtry-with-resources
statement to automatically manage these resources. This approach ensures that resources are closed correctly even if an exception occurs .
summarize
The destruction of Java objects mainly relies on the garbage collection mechanism to automatically manage. Developers should focus on rationally organizing their code structure, releasing resources that are no longer in use in a timely manner, and trying to adopt modern language features (such as thetry-with-resources
) to help manage resources. Also, avoid usingfinalize()
methods to perform cleanup, as the effects of such methods are unreliable and unpredictable. With these practices, memory usage can be effectively managed to improve program robustness and performance.
GC Garbage Collector
Garbage Collector (GC) is a memory management mechanism in languages such as Java, which is used to automatically detect and reclaim memory space occupied by objects that are no longer in use.The exact implementation of GC and the timing of its triggering depends on the implementation and configuration of the JVM (Java Virtual Machine), but programmers usually do not need to, nor should they, directly intervene in the work of GC.
GC (Garbage Collection) garbage collector is Java and other languages to automatically manage the program memory mechanism, is responsible for recycling those memory objects that are no longer used by the program, in order to free up memory space for the program to continue to use. The following is a detailed explanation of the GC garbage collector:
I. Basic Principles of GC
- goal: Reclaims objects in memory that are no longer being used, freeing the memory space they occupy.
- tag editor: The method used for recycling in GC is called collector.
- Optimization goals: Since GC needs to consume some resources and time, Java, after analyzing the life cycle characteristics of the object, collects the object according to the new generation and the old generation in order to shorten the pause caused by GC to the application as much as possible.
II. Algorithm of GC
GC uses different algorithms to detect garbage objects and reclaim the memory space they occupy. The commonly used algorithms include:
-
reference counting algorithm:
- principle: Maintain a reference count for each object, when an object references the object, the count is increased by 1; when the reference is invalid, the count is decreased by 1. When the reference count is 0, it means that the object is no longer used and can be recycled.
- vantage: Simple to implement and efficient to execute.
- drawbacks: Can't fix circular references.
-
Reachability Analysis Algorithm:
- principle: Starting from a series of root objects called GC Roots, all reachable objects are searched through the reference chain, and the remaining unmarked objects are garbage objects.
- GC Roots: This includes objects referenced in the virtual machine stack, objects referenced by class static attributes in the method area, objects referenced by constants in the method area, objects referenced by JNI in the local method stack, and so on.
- vantage: The ability to accurately identify garbage objects is the algorithm used by mainstream virtual machines.
-
Mark-Clear Algorithm:
- course of events: First mark all the objects that need to be recycled and then remove them uniformly.
- drawbacks: Inefficient and creates memory fragmentation.
-
replication algorithm:
- principle: Divide memory into two equal-sized chunks and use only one of them at a time. When this block of memory runs out, the surviving objects are copied to the other block of memory, and then all objects in the original memory are cleared.
- vantage: Solves the memory fragmentation problem and is simple to implement.
- drawbacks: Memory utilization is low, half of what it was.
-
Marking-Organizing Algorithm:
- principle: After marking all objects to be reclaimed, have all surviving objects move toward one end of memory, and then clear the memory directly outside the end boundary.
- vantage: Memory fragmentation is solved and memory utilization is high.
- drawbacks: Higher costs.
-
generational algorithm:
- principle: The memory is divided into chunks (e.g., new generation and old generation) according to the difference in object survival cycles; new generation has short object survival cycles and uses the copying algorithm; old generation has long object survival cycles and uses the marking-sorting algorithm.
III. Types of GC
-
Minor GC (New Generation GC):
- trigger condition: Triggered when the new generation (including Eden and Survivor zones) cannot allocate memory space for the newborn object.
- specificities: High frequency of occurrence, but fast recovery.
-
Major GC (old age GC):
- Clearance targets: Mainly cleaning up objects from the old era.
- specificities: Occurs relatively infrequently, but has a large number of recovery objects and may take a long time.
-
Full GC:
- Scope of clearance: Cleans up the entire heap space, including young-generation, old-generation, and meta-space (Java 8 and above).
- specificities: The impact is the most widespread and may result in longer application pauses.
IV. Types of GC garbage collectors
Java provides a variety of garbage collectors to suit different application scenarios and performance needs. Common garbage collectors include:
-
Serial Garbage Collector (SGC):
- specificities: Single-threaded execution of garbage collection, suitable for small applications or single-core CPU environments.
-
Parallel Garbage Collector (Parallel Garbage Collector):
- specificities: Multi-threaded execution of garbage collection, improving the efficiency of garbage collection, is the default garbage collector of the JVM.
-
Concurrent Marked Scan Garbage Collector (CMS Garbage Collector):
- specificities: Aims to minimize stopping time and is suitable for applications with high stopping time requirements.
-
G1 Garbage Collector:
- specificities: For server-side applications, dividing heap memory into multiple regions and garbage collecting concurrently, while taking into account both downtime and throughput.
V. Summary
GC garbage collector is an important mechanism for Java and other languages to automatically manage memory, through different algorithms and recyclers to realize the recovery of garbage objects and the release of memory space. In practice, you need to choose the right garbage collector according to the characteristics and needs of the application.
10. Anonymous objects
An anonymous object is an object that is used directly when the object is created, rather than first being assigned to a reference variable. Anonymous objects are typically used only once and are primarily used to invoke the object's methods. Since anonymous objects do not have reference variables, they have a very limited scope of use and are reclaimed by the garbage collector as soon as the called method is executed.
III. Relationship between classes
Six relationships between classes
I. Succession relations
Inheritance refers to the ability of a class (called a subclass, subinterface) to inherit the functionality of another class (called a parent class, parent interface) and can add new functionality of its own. In Java inheritance relationships are clearly identified by the keyword extends and are generally not controversial at design time. In UML class diagram design, inheritance is represented by a solid line with a hollow triangular arrow pointing from a subclass to a parent class, or a subinterface to a parent interface.
II. Realization of the relationship
An implementation refers to a class class that implements the functionality of an interface interface (which can be more than one). Implementations are the most common relationship between classes and interfaces. In Java such relationships are clearly identified by the keyword implementations and are generally uncontroversial at design time. In UML class diagram design, implementations are represented by a dotted line with a hollow triangular arrow pointing from the class to the implemented interface.
III. Dependencies
A simple understanding, dependency is a class A used to another class B, and this use of the relationship is contingent, temporary, very weak, but the changes in class B will affect class A. For example, a person to cross the river, you need to borrow a boat, at this time the relationship between the person and the boat is a dependency. The relationship between a person and a boat is a dependency, which is expressed at the code level as class B being used as a parameter by class A in a method. In UML class diagrams, dependencies are represented by dotted lines with arrows pointing from class A to class B.
IV. Linkages
An association is a strong dependency at the semantic level between two classes, such as me and my friend, which is stronger than a dependency, does not have the contingency of a dependency, the relationship is not temporary, it is generally long-term, and the relationship is generally equal. Associations can be unidirectional and bidirectional. At the code level, it may be that the associated class B appears as a class attribute in the associated class A, or that the associated class A refers to a global variable of type associated class B. In UML class diagram design, the association relationship is represented by a solid line with an arrow pointing from the associated class A to the associated class B.
V. Aggregate relationships
Aggregation is a special case of an association relationship, which embodies the relationship between the whole and its parts, i.e., the has-a relationship. At this point the whole and the part are separable from each other, they can have their own life cycle, and the part can belong to more than one whole object, or can be shared by more than one whole object. For example, the relationship between a computer and a CPU, a company and its employees, and so on. Expressed at the code level, it is consistent with the association relationship, which can only be distinguished from the semantic level. In UML class diagram design, the aggregation relationship is represented by a hollow diamond with a solid line. (The diamond points to the whole)
VI. Combined relationships
Combination is also a special case of an associative relationship that is stronger than aggregation, also known as strong aggregation. It also embodies the relationship between the whole and the parts, but at this point the whole and the parts are indistinguishable, and the end of the life cycle of the whole implies the end of the life cycle of the parts, such as a human being and the human brain. The performance in the code level, and the association relationship is consistent, can only be distinguished from the semantic level. In UML class diagram design, the combination relationship is represented as a solid diamond with a solid line.
summarize
For the two relationships, inheritance and implementation, they reflect the vertical relationship between a class and a class, or a class and an interface. The other four relationships reflect referential, horizontal relationships between a class and a class, or a class and an interface. Associative relationships reflect strong dependencies, while aggregation and combination are special cases of associative relationships, distinguished by the strength of the whole versus the parts.
High cohesion and low coupling are core principles in software design that aim to improve the quality, maintainability, scalability and flexibility of software systems. The following is a detailed explanation of these two principles:
Maximum design principles
I. High cohesion
define:
High cohesion refers to the strong correlation between elements within a module or component, i.e., the functionality and data within the module are closely related to form a highly independent whole. A highly cohesive design helps to improve code readability, maintainability and reusability.
Features & Benefits:
- functional relevance: Placing code with the same or similar functionality in the same module makes the organization of the code clearer and easier to understand.
- single duty: Each module or component is responsible for only one function, avoiding one module taking on too many responsibilities, thus improving the testability and maintainability of the module.
- Data localization: Hiding the data inside the module and exposing only the necessary interfaces for external use reduces the dependency between modules and improves module independence.
II. Low coupling
define:
Low coupling refers to modules or components that are less connected and less dependent on each other. A low-coupling design helps to reduce the tightness between the components of the system and improves the flexibility and scalability of the system.
Features & Benefits:
- Interface independence: Interfaces between modules should be independent of the implementation, exposing only the necessary interfaces for external use and reducing dependencies between modules.
- loose coupling: Modules should be loosely related to each other, and changes in one module should not affect the others too much.
- dependency inversion: Dependencies between modules should be realized through an abstraction layer, where higher-level modules do not depend on the concrete implementation of lower-level modules, but communicate with each other through interfaces.
Applications and impacts
The design principles of high cohesion and low coupling have a wide range of applications in software development, and their impact is mainly reflected in the following aspects:
- Improve code quality: Through the design of high cohesion, the code is organized more clearly and is easy to understand and maintain; through the design of low coupling, the dependency between modules is reduced and the impact of modifying one module on other modules is reduced.
- Enhanced system flexibility: The low-coupling design allows for looser connections between system components, facilitating modification or replacement of individual components without affecting others.
- Enhanced system scalability: The design principles of high cohesion and low coupling make it easier to add new functionality or extend existing functionality without having to make large-scale changes to the overall architecture.
- Promoting teamwork: The high cohesion design makes the responsibilities of each module or component clearer, which helps the division of labor and cooperation among team members; the low coupling design reduces the dependency relationship between modules and lowers the communication cost among team members.
To summarize, high cohesion and low coupling is one of the highest design principles in software design, which is of great significance for improving the quality, maintainability, scalability and flexibility of software systems. In the process of software development, developers should always adhere to this principle in order to construct a more excellent and reliable software system.