Lecture
In object-oriented programming a class defines the common aspects of the objects created from that class. The capabilities of a class differ from one programming language to another, but typically the common aspects consist of state (variables) and behavior (methods), each of which is tied either to a particular object or to all objects of that class.
An object's state can differ between each instance of the class, whereas the class's state is shared by all of them. An object's methods involve access to the object's state (through an implicit or explicit parameter that refers to the object), whereas class methods do not.
If the language supports inheritance, a class can be defined on the basis of another class, taking on all of its state and behavior, plus additional state and behavior that further specialize the class. The specialized class is a subclass, and the class it is based on is its superclass.

In object-oriented programming (OOP) there are several kinds of classes, each with its own features and purpose. Here are the main ones:
Ordinary (concrete, classic) class - An object can be created. Contains ordinary methods and properties.
Base Class:
Derived Class:
Abstract Class:
Interface:
Concrete Class:
Nested class (inner / nested class) - a class defined inside another class.:
Static Class:
In DDD, a set of domain object types is distinguished — these are logical categories of classes that reflect the rules of the domain.
| Class kind | Meaning | Example |
|---|---|---|
| Entity | A unique object with an identifier; identity matters, not the data | User, Order, Account |
| Value Object | No ID, only the data matters, immutable | Money, Coordinates, Email |
| Aggregate | A group of entities and value objects united by logic | Order + OrderItem[] |
| Aggregate Root | The main entity within an aggregate | Order (controls OrderItem) |
| Domain Service | Logic that does not belong to an entity | PaymentService, PriceCalculator |
| Domain Event | A fact that occurred in the domain | OrderCreated, PaymentReceived |
| Factory | Creation of complex entities and aggregates | OrderFactory |
| Repository | Interface for accessing aggregates | OrderRepository |
Application classes vs. domain classes
| Level | Class type | Purpose |
|---|---|---|
| Domain | Entity, Value Object, Aggregate, Domain Service, Event | Business model |
| Application | Application Service | Orchestration of business processes |
| Infrastructure | Repository Implementation, ORM Models, Adapters | Data storage, external services |
| UI / Interface | Controllers / Presenters / ViewModels | Interaction with the user |
// Value Object
public record Email(string Value);
// Entity
public class User {
public Guid Id { get; }
public Email Email { get; private set; }
public User(Guid id, Email email) { Id = id; Email = email; }
}
// Domain Service
public class UserRegistrationService
{
public User Register(Email email) {
return new User(Guid.NewGuid(), email);
}
}
Value Object — immutable, equal by value
Aggregate — protects data integrity
Domain Service — logic that "does not belong" to an object
Repository — storage for aggregates
Anonymous classes are classes that are created on the fly, without an explicit name declaration. They are used when a one-off object with custom logic is needed, without creating a separate class.
Main properties of anonymous classes:
The anonymous class mechanism lets you declare a class and immediately create an instance of it. This makes the code concise and expressive. Anonymous classes are convenient to use when the class is only needed once.
The main feature is that an anonymous class has no name. An anonymous class can be a subclass of an existing class or an implementation of an interface.
Main properties of anonymous classes:
The example below declares two anonymous classes that are subclasses of PrintManager. Both anonymous classes are different, unique classes.
PrintManager manager1 = new PrintManager() {
@Override
public void printFile(File file) {
super.printFile(file);
}
};
PrintManager manager2 = new PrintManager() {
@Override
public void printFile(File file) {
super.printFile(file);
}
};
These kinds of classes help organize code, improve its readability and reusability, and promote a more flexible and scalable software design.
In object-oriented programming (OOP), classes can be divided into different categories depending on their purpose.
Purpose:
Examples:
Code example:
public class EnemyManager
{
private List enemies = new List();
public void SpawnEnemy(Vector3 position)
{
Enemy newEnemy = new Enemy(position);
enemies.Add(newEnemy);
}
public void RemoveEnemy(Enemy enemy)
{
enemies.Remove(enemy);
}
}
Purpose:
Examples:
Code example:
public class AI_Agent {
private Vector3 position;
public void MoveTo(Vector3 target)
{
// Logic for moving to the target
}
public void MakeDecision()
{
// Decision-making logic
}
}
Purpose:
Examples:
Code example:
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public void TakeDamage(int amount)
{
Health -= amount;
}
}
Purpose:
Examples:
Code example:
public static class LoggerService {
public static void Log(string message) {
Console.WriteLine($"[{DateTime.Now}] {message}");
}
}
Purpose:
Examples:
Code example:
public static class MathHelper {
public static float Clamp(float value, float min, float max)
{
return Math.Max(min, Math.Min(value, max));
}
}
Purpose:
Code example:
public class EnemyFactory
{
public static Enemy CreateEnemy(string type)
{
if (type == "zombie") return new Enemy(100, 10);
if (type == "robot") return new Enemy(200, 20);
return new Enemy(50, 5);
}
}
public class PhysicsSystem
{
private static PhysicsSystem instance;
private List objects = new List();
private PhysicsSystem() { }
// Private constructor (Singleton)
public static PhysicsSystem Instance
{
get { if (instance == null) instance = new PhysicsSystem(); return instance; }
}
public void UpdatePhysics(float deltaTime)
{
foreach (var obj in objects) { obj.ApplyPhysics(deltaTime);
}
}
}
Key points:
Most often a singleton (a single instance).
Manages global state (all physics objects).
Has a clearly defined area of responsibility in the system.
8. Service Classes
public static class LoggerService
{
public static void Log(string message)
{
Console.WriteLine($"[{DateTime.Now}] {message}");
}
}
Key points:
Most often static.
Does not manage global processes but provides utility methods.
Can be used anywhere in the code without depending on a specific object.
A provider class is an object that provides access to resources, services, or data. It encapsulates the logic for retrieving information so that the code is more flexible and modular.
Main properties of a provider class:
Provides access to external resources (DB, API, files, configuration).
Separates data-retrieval logic from business logic (separation of concerns).
Often implemented as a Singleton or through Dependency Injection (DI).
Can cache data to improve performance.
Examples of provider classes
Data Provider
Example in C#:
public class DataProvider
{
private readonly string connectionString;
public DataProvider(string connString)
{
this.connectionString = connString;
}
public List GetUsers()
{
// A SQL query can be executed here
return new List { "Alice", "Bob", "Charlie" };
}
}
Here DataProvider is responsible for data access (for example, from a DB).
Example in C#:
public class ConfigProvider
{
private Dictionary settings = new Dictionary { { "AppName", "MyApp" }, { "Version", "1.0" } };
public string GetSetting(string key)
{
return settings.ContainsKey(key) ? settings[key] : "Not Found";
}
}
Used for working with the application's configuration (for example, retrieving settings).
Example in C#:
public class WeatherProvider
{
private readonly HttpClient httpClient = new HttpClient();
public async Task GetWeatherAsync(string city)
{
string url = $"https://intellect.icu/{city}";
return await httpClient.GetStringAsync(url);
}
}
This class encapsulates requests to the API, making it easy to change the data source.
When should you use providers?
You need to separate the data-retrieval logic from the business logic.
You need to make the code more flexible (the data source can easily be swapped out).
When the provider might need to change (for example, switching API services without rewriting code).
Conclusion:
A provider class is a layer responsible for access to resources (data, files, APIs, settings), which keeps the code modular.
10. Mapping class
A Mapping class is typically used to map objects or convert data from one structure to another. It can be used in various contexts, such as converting data between different layers of an application, converting objects into a format convenient for storage or transmission (for example, into JSON or XML), or mapping between different models.
Mapping can fall under several class types depending on the context:
Functional Classes
If Mapping is used to transform or process data, for example, from one format to another, it falls under service classes. For example:
Repository Classes
In some cases, Mapping can be part of a repository, when database objects need to be mapped to the application's business objects.
Helper/Utility Classes
When a Mapping class performs a simple data conversion or is utility-like, for example, converting objects to strings or back, it can be regarded as a helper class.
Suppose we have two classes: Model and DTO. We use a Mapping class to convert between them.
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
public class DTO
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Mapper
{
public DTO MapToDTO(Model model)
{
return new DTO { Id = model.Id, Name = model.Name };
}
public Model MapToModel(DTO dto)
{
return new Model { Id = dto.Id, Name = dto.Name };
}
}
In this example, Mapper is a Functional Class, since its main job is data conversion, which is often carried out through service classes.
So Mapping generally belongs to functional classes or helper classes, depending on how it is used.
Here is a summary table of the main class types in OOP, including systems, services, managers, agents, entities, utilities, factories, repositories, and DTOs.
Table comparing class types in OOP
| Class type | Purpose | Stores state? | Example | Implementation |
|---|---|---|---|---|
| System classes | Manage global processes (physics, input, rendering) | Yes | PhysicsSystem, InputSystem, AudioSystem | Singleton, manages system state |
| Service classes | Provide helper functions (logging, HTTP requests, files) | No (or temporarily) | LoggerService, FileService, NetworkService | static class or via Dependency Injection (DI) |
| Manager classes | Manage groups of objects or processes (creation, storage, deletion) | Yes | GameManager, SceneManager, DatabaseManager | Contains a collection of objects, management methods |
| Agent classes | Represent autonomous objects with logic (NPCs, robots, bots) | Yes | AI_Agent, TradingAgent, RobotAgent | Encapsulates behavior logic, reacts to changes |
| Entity classes | Describe objects of the domain (player, enemy, product) | Yes | Player, Enemy, Car, Product | Contains properties and methods for managing the object |
| Utility classes | A set of helper static methods (math, string handling) | No | MathHelper, StringUtils | static methods, do not store data |
| Factory classes | Create objects, hiding the details of their creation | No | EnemyFactory, CarFactory | Static or ordinary classes with Create() methods |
| Repository classes | Responsible for data access (DB, files) | Yes | UserRepository, ProductRepository | CRUD methods (Create, Read, Update, Delete), works with the DB |
| DTO classes (Data Transfer Object) | Carry data between application layers (UI ⇄ DB) | Yes (data only) | UserDTO, OrderDTO | Only properties, no business logic |
| Provider classes | provides access to resources, services, or data (DB, API, files), or describes interface implementations in dependency inversion, | Yes | DataProvider, ConfigProvider, WeatherProvider |
Singleton or Dependency Injection, can cache data |
public class UserRepository
{
private List users = new List();
public void Add(User user) => users.Add(user);
public User GetById(int id) => users.FirstOrDefault(u => u.Id == id);
public void Remove(User user) => users.Remove(user);
}
public class UserDTO
{
public string Name { get; set; }
public int Age { get; set; }
}
Use system classes when you need to manage the application's core processes (for example, physics, rendering, input).
Use services when you need to separate out helper functions (logging, networking, the file system).
Put simply:
This separation helps structure the code, simplifies maintenance, and improves readability.
| System Classes | Service Classes | |
|---|---|---|
| Function | Manage the application's core processes | Provide helper functions |
| Stores state | Most often store data (for example, a list of all physics objects) | Most often do not store state |
| Lifecycle | Run for the application's entire lifetime | Used as needed |
| Implementation | Most often Singleton (or a managed system) | Most often static or via Dependency Injection |
| Example | PhysicsSystem, AudioSystem, InputSystem | LoggerService, FileService, NetworkService |
Systems manage global processes.
Services provide helper functions.
Managers manage groups of objects.
Agents act autonomously.
Entities describe real-world objects.
Utilities contain static methods.
Factories create objects.
Repositories manage data.
DTOs transfer data between application layers.
In object-oriented programming (OOP), collection classes and model classes play important roles in managing data and representing it.
Collection classes are designed to store and manage groups of objects. They provide convenient methods for adding, removing, searching, and sorting elements.
List numbers = new List { 1, 2, 3, 4, 5 };
numbers.Add(6);
numbers.Remove(3);
Console.WriteLine(numbers.Count);
Types of collections:
Model classes describe the structure of the data used in a system. They represent objects of the domain (for example, users, products, orders).
public class UserModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Usage:
Here is a table for model classes and collection classes in OOP:
| Class type | Purpose | Stores state? | Example | Implementation |
|---|---|---|---|---|
| Model Classes | Describe the domain's data structure (users, products, orders) | Yes | UserModel, ProductModel, OrderModel | An ordinary class with properties (get/set), can be used in ORMs (Entity Framework, Hibernate) |
| Collection Classes | Store and manage groups of objects (search, sort, filter) | Yes | List, Dictionary, Queue | Use standard data structures (List, Dictionary, Queue, Stack), may implement iterators |
| Characteristic | Collection Classes | Model Classes |
|---|---|---|
| Purpose | Managing a group of objects | Describing a data structure |
| Contains logic? | Yes (adding, removing, searching) | No (only properties) |
| Example | List | UserModel |
| Usage | Lists, dictionaries, queues | ORM, API, UI |
Conclusion:
As an instance of a class, an object is created from a class through instantiation . Memory is allocated and initialized for the object's state, and a reference to the object is provided to the consuming code. The object can be used until it is destroyed — its state memory is released.
Most languages allow custom logic to be implemented for lifecycle events through the constructor and destructor .
An object expresses a data type as an interface — the type of each member variable and the signature of each member function (method). A class defines the implementation of the interface, and instantiating a class results in the creation of an object that exposes the implementation through the interface. In terms of type theory, a class is an implementation — a concrete data structure and a set of subroutines — whereas a type is an interface . Different (concrete) classes can create objects of the same (abstract) type (depending on the type system). For example, the type (interface) Stack might be implemented by SmallStack , which is fast for small stacks but scales poorly, and by ScalableStack , which scales well but has high overhead for small stacks.

UML notation for classes
A class contains descriptions of data fields (also called properties , fields , data members or attributes ). These are typically field types and names that will be bound to state variables at program runtime; these state variables belong either to the class itself or to specific instances of the class. In most languages, the structure defined by a class determines the memory layout used by its instances. Other implementations are possible: for example, objects in Python use associative key-value containers.
Some programming languages, such as Eiffel, support the specification of invariants as part of a class definition and enforce them through the type system. Encapsulation of state is necessary to make it possible to enforce a class's invariants.
The behavior of a class or its instances is defined by means of methods . Methods are subroutines capable of operating on objects or classes. These operations can change an object's state or simply provide ways of accessing it. There are many kinds of methods, but their support varies from language to language. Some types of methods are created and invoked by programmer-written code, while other special methods, such as constructors, destructors and conversion operators, are created and invoked by compiler-generated code. A language may also allow the programmer to define and invoke these special methods.
Every class implements (or realizes ) an interface, providing structure and behavior. The structure consists of data and state, while the behavior consists of the code that determines how the methods are implemented. [ 8 ] There is a distinction between defining an interface and implementing that interface; however, this boundary is blurred in many programming languages, since class declarations both define and implement the interface. Some languages, however, provide features that separate the interface from the implementation. For example, an abstract class can define an interface without providing an implementation.
Languages that support class inheritance also allow classes to inherit the interfaces of the classes they are derived from.
For example, if “class A” inherits from “class B” and “class B” implements the interface “interface B”, then “class A” also inherits the functionality (constant and method declarations) provided by “interface B”.
In languages that support access specifiers , a class's interface is considered to be the set of the class's public members, including both methods and attributes (through implicit getter and setter methods ); any private members or internal data structures are not intended to be depended on by outside code and thus are not part of the interface.
Object-oriented programming methodology dictates that the operations of any class interface should be independent of one another. This leads to a layered design, in which clients of the interface use the methods declared in the interface. The interface imposes no requirement on clients to invoke the operations of a single interface in any particular order. This approach has the advantage that client code can assume that the interface's operations are available for use whenever the client has access to the object
Example of a class interface
The buttons on the front panel of a television are an interface between you and the wiring on the other side of its plastic case. You press the “power” button to turn the television on or off. In this example, your particular television is the instance, each method is represented by a button, and all the buttons together make up the interface (other televisions of the same model as yours will have the same interface). In its most common form, an interface is a specification of a group of related methods without any associated implementation of those methods.
A television also has many attributes , such as its size and whether it supports color, which together make up its structure. A class is a complete description of a television, including its attributes (structure) and buttons (interface).
Getting the total number of televisions manufactured could be a static method of the television class. This method is associated with the class but lies outside the scope of each instance of the class. Another example is a static method that finds a particular instance from the set of all television objects.
Below is a common set of access specifiers :
Although many object-oriented languages support the access specifiers listed above, their semantics can differ.
Object-oriented design uses access specifiers in combination with careful design of the implementations of public methods to enforce class invariants — constraints on the state of objects. A common use of access specifiers is to separate a class's internal data from its interface: the internal structure is made private, while public accessor methods can be used to inspect or modify such private data.
Access specifiers do not necessarily control visibility , in the sense that even private members can be visible to outside client code. In some languages, an inaccessible but visible member can be referenced at runtime (for example, via a pointer returned by a member function), but an attempt to use it by referring to the member's name from client code will be prevented by type checking.
Different object-oriented programming languages enforce member accessibility and visibility to varying degrees, and depending on the language's type system and compilation policies, this is enforced either at compile time or at runtime . For example, the Java language does not allow client code that accesses a class's private data to compile. In C++, private methods are visible but not accessible in the interface; however, they can be made invisible by explicitly declaring fully abstract classes that represent the class's interfaces.
Some languages provide other accessibility schemes:
Conceptually, a superclass is a superset of its subclasses. For example, GraphicObject might be a superclass of Rectangle and Ellipse , while Square would be a subclass of Rectangle . These are also subset relationships in set theory, i.e., all squares are rectangles, but not all rectangles are squares.
A common conceptual mistake is to mistake a part-of relationship for a subclass relationship. For example, a car and a truck are kinds of vehicles, and it would be appropriate to model them as subclasses of a vehicle class. However, it would be a mistake to model the parts of a car as subclass relationships. For example, a car consists of an engine and a body, but it would be wrong to model the engine or the body as a subclass of the car.
In object-oriented modeling, these kinds of relationships are usually modeled as properties of objects. In this example, the Car class would have a property called parts . parts would be typed to hold a collection of objects, such as instances of Body , Engine , Tires , etc. Object-modeling languages such as UML include the ability to model various aspects of “part-of” and other kinds of relationships – data such as the cardinality of objects, constraints on input and output values, and so on. This information can be used by developer tools to generate additional code beyond the basic data definitions for objects, such as error checking in get and set methods.
One important question when modeling and implementing a system of object classes is whether a class may have one or several superclasses. In the real world, with real sets, it is rare to find sets that do not intersect with more than one other set. However, while some systems, such as Flavors and CLOS, provide the ability for more than one parent to do this at runtime, this introduces a complexity that many in the object-oriented community consider to run counter to the purpose of using object classes in the first place. Understanding which class will be responsible for handling a message can become complicated when dealing with more than one superclass. If used carelessly, this feature can introduce some of the same systemic complexity and ambiguity that classes were designed to avoid.
Most modern object-oriented languages, such as Smalltalk and Java, require single inheritance at runtime. For these languages, multiple inheritance can be useful for modeling, but not for implementation.
However, objects in Semantic Web applications have several superclasses. The instability of the Internet requires this level of flexibility, and technology standards such as the Web Ontology Language (OWL) are designed to support it.
A related question is whether a class hierarchy can be modified at runtime. Languages such as Flavors, CLOS and Smalltalk support this feature as part of their metaobject protocols . Because classes are themselves first-class objects, they can be made to dynamically change their structure by sending them appropriate messages. Other languages that focus more on strict typing, such as Java and C++, do not allow the class hierarchy to be modified at runtime. Semantic Web objects have the ability to change classes at runtime. The rationale is similar to the rationale for allowing multiple superclasses: the Internet is so dynamic and flexible that managing this variability requires dynamic changes to the hierarchy.
Although many class-based languages support inheritance, inheritance is not an inherent aspect of classes. An object-based language (i.e., classic Visual Basic ) supports classes but does not support inheritance.
A programming language may support various class-relationship features.
Classes can be composed of other classes, thereby establishing a compositional relationship between the containing class and its embedded classes. A compositional relationship between classes is also commonly known as a has-a relationship. For example, a "Car" class might be composed of, and contain, an "Engine" class. Thus, Car has an Engine. One aspect of composition is containment, which is the containment of instances of components by the instance that has them. If the containing object holds the component instances by value, the components and their containing object have a similar lifetime . If the components are held by reference, they may not have a similar lifetime. For example, in Objective-C 2.0:
This Car class has an instance of NSString ( a string object ), an Engine, and an NSArray (an array object).
Classes can be derived from one or more existing classes, thereby establishing a hierarchical relationship between the classes being derived from ( base classes , parent classes , or superclasses ) and the derived class (child class or subclass). The relationship of a derived class to the classes it is derived from is commonly known as an is-a relationship. For example, a "Button" class might be derived from a "Control" class. Consequently, a Button is a Control. The structural and behavioral members of the parent classes are inherited by the child class. Derived classes may define additional structural members (data fields) and behavioral members (methods) beyond those they inherit, and are therefore specializations of their superclasses. In addition, derived classes may override inherited methods, if the language allows it.
Not all languages support multiple inheritance. For example, Java allows a class to implement multiple interfaces, but to inherit from only one class. If multiple inheritance is allowed, the hierarchy is a directed acyclic graph (or DAG for short); otherwise it is a tree . The hierarchy has classes as nodes and inheritance relationships as links. Classes at the same level are more likely to be related than classes at different levels. The levels of this hierarchy are called layers or levels of abstraction.
Example (simplified Objective-C 2.0 code from the iPhone SDK):
@interface UIResponder : NSObject //... @interface UIView : UIResponder //... @interface UIScrollView : UIView //... @interface UITableView : UIScrollView //...
In this example, UITableView is a UIScrollView , is a UIView , is a UIResponder , is an NSObject.
In object-oriented analysis and in the Unified Modeling Language (UML), an association between two classes represents a collaboration between the classes or their corresponding instances. Associations have direction; for example, a bidirectional association between two classes indicates that both classes are aware of their relationship. Associations may be labeled according to their name or purpose
An association role is specified at the end of an association and describes the role of the corresponding class. For example, the role “subscriber” describes the way instances of the class “Person” participate in the “subscribes to” association with the class “Magazine”. In addition, “Magazine” has the role “subscribed magazine” in the same association. An association role's multiplicity describes how many instances correspond to each instance of the other class in the association. Common multiplicities are “0..1”, “1..1”, “1..*” and “0..*”, where “*” indicates any number of instances.
There are many categories of classes, some of which overlap.
In a language that supports inheritance, an abstract class or abstract base class ( ABC ) is a class whose instance cannot be created directly. In contrast, a concrete class is a class whose instance can be created directly. Instantiation of an abstract class can only occur indirectly, through a concrete subclass .
An abstract class is either explicitly marked as such, or it may simply specify abstract methods (or virtual methods ). An abstract class can provide implementations of some methods, as well as specify virtual methods through signatures that must be implemented by the direct or indirect descendants of the abstract class. Before a class derived from an abstract class can be instantiated, all abstract methods of its parent classes must be implemented by some class in the derivation chain.
Most object-oriented programming languages allow the programmer to specify which classes are considered abstract, and do not allow instances of them to be created. For example, Java , C# and PHP use the abstract keyword. In C++, an abstract class is a class that has at least one abstract method specified by the corresponding syntax in that language (a pure virtual function in C++).
A class consisting only of pure virtual methods is called a pure abstract base class (or pure ABC ) in C++, and is also known to users of the language as an interface . Other languages, notably Java and C#, support a variant of abstract classes called an interface, through a keyword in the language. In these languages, multiple inheritance is not allowed, but a class may implement multiple interfaces. Such a class may contain only abstract public methods.
In some languages, classes can be declared in scopes other than the global scope. There are various types of such classes.
An inner class is a class defined inside another class. The relationship between an inner class and its containing class can also be viewed as another type of class association. An inner class is usually not associated with instances of the enclosing class and is not created together with its enclosing class. Depending on the language, it may or may not be possible to reference the class from outside the enclosing class. A related concept is inner types , also known as an inner data type or nested type , which are a generalization of the concept of inner classes. C++ is an example of a language that supports both inner classes and inner types (through typedef declarations).
A local class is a class defined inside a procedure or function. This structure restricts references to the class name to the scope where the class is declared. Depending on the language's semantic rules, there may be additional restrictions on local classes compared to non-local ones. One common restriction is a prohibition on methods of the local class accessing local variables of the enclosing function. For example, in C++ a local class can reference static variables declared inside its enclosing function, but cannot access the function's automatic variables .
A metaclass is a class whose instances are classes. A metaclass describes the common structure of a collection of classes and can implement a design pattern or describe specific kinds of classes. Metaclasses are often used to describe frameworks .
In some languages, such as Python , Ruby or Smalltalk , a class is also an object; thus, every class is an instance of a unique metaclass built into the language. The Common Lisp Object System (CLOS) provides metaobject protocols (MOP) for implementing these classes and metaclasses.
A sealed class cannot be subclassed. In essence, it is the opposite of an abstract class, which must be derived from in order to be used. A sealed class is implicitly concrete .
A class is declared as sealed using the sealed keyword in C#, final in Java, or PHP.
For example, Java's String class is marked as final .
Sealed classes can allow the compiler to perform optimizations that are not available for classes that can be subclassed.
An open class can be modified. Usually, a running program cannot be modified by clients. Developers can often modify some classes, but usually cannot modify standard or built-in ones. In Ruby, all classes are open. In Python, classes can be created at runtime, and all of them can be modified afterward. Objective-C categories allow the programmer to add methods to an existing class without needing to recompile that class or even have access to its source code.
Some languages have special support for mixins , although in any language with multiple inheritance a mixin is simply a class that does not represent an is-a-type-of relationship. Mixins are typically used to add the same methods to several classes; for example, a UnicodeConversionMixin class might provide a method named unicode_to_ascii when included in the FileReader and WebPageScraper classes, which have no common parent.
In languages that support this feature, a partial class is a class whose definition can be split into several parts, either in a single source file or across multiple files. The parts are merged at compile time, making the compiler's output the same as for a non-partial class.
The main motivation for introducing partial classes is to make it easier to implement code generators , such as visual designers . Otherwise, it is a challenge or a compromise to develop code generators that can manage generated code when it is interleaved with code written by the developer. By using partial classes, a code generator can handle a separate file or a coarse-grained partial class within a file, and is thus freed from the complexity of inserting generated code by means of extensive parsing, which increases compiler efficiency and eliminates the potential risk of corrupting the developer's code. In a simple implementation of partial classes, the compiler can perform a pre-compilation phase in which it "merges" all the parts of the partial class. Compilation can then proceed as usual.
Other benefits and effects of the partial class feature include:
Partial classes existed in Smalltalk under the name Class Extensions for a considerable time. With the advent of .NET Framework 2, Microsoft introduced partial classes, supported in both C# 2.0 and Visual Basic 2005. WinRT also supports partial classes.
Non-instantiable classes allow programmers to group fields and methods of a class that are available at runtime without an instance of the class. Indeed, instantiation is prohibited for this type of class.
For example, in C# a class marked as "static" cannot be instantiated, can only have static members (fields, methods, etc.), cannot have instance constructors, and is sealed .
An unnamed class or anonymous class is not bound to a name or identifier when it is defined. This is analogous to named and unnamed functions .
The benefits of organizing software into object classes fall into three categories
Object classes promote rapid development because they reduce the semantic gap between the code and its users. Systems analysts can communicate with both developers and users using essentially the same vocabulary, talking about accounts, customers, invoices, and so on. Object classes often promote rapid development because most object-oriented environments come with powerful debugging and testing tools. Instances of classes can be inspected at runtime to verify that the system is behaving as expected. In addition, instead of getting core memory dumps, most object-oriented environments have interpreted debugging capabilities, so that a developer can precisely analyze where in the program an error occurred and can see which methods were called, on which arguments, and with what arguments.
Object classes ease maintenance through encapsulation. When developers need to change an object's behavior, they can localize the change to just that object and its constituent parts. This reduces the likelihood of unwanted side effects from maintenance enhancements.
Software reuse is also an important benefit of using object classes. Classes facilitate reuse through inheritance and interfaces. When new behavior is required, it can often be achieved by creating a new class and having that class inherit the default behavior and data of its superclass, then appropriately adjusting some aspects of the behavior or data. Reuse through interfaces (also known as methods) occurs when another object wants to invoke (rather than create a new kind of) some object class. This method of reuse eliminates many common errors that can creep into software when one program reuses code from another.
As a data type, a class is usually regarded as a compile-time construct. A language or library may also support prototype or factory metaobjects , which represent class information at runtime or even represent metadata that provides access to reflective programming (reflection) facilities and the ability to manipulate data structure formats at runtime. Many languages distinguish this kind of runtime type information from the class on the grounds that this information is not needed at runtime. Some dynamic languages do not make a strict distinction between runtime and compile-time constructs and, as a result, may not distinguish between metaobjects and classes.
For example, if Human is a metaobject representing the Person class, then instances of the Person class can be created using the capabilities of the Human metaobject.
Unlike creating an object from a class, some programming contexts support creating an object by copying (cloning) a prototype object.
Depending on the programming language and implementation, classes can be stored in different data structures. Here are the main options:
Used in compilers and interpreters to store information about classes, variables and functions.
Usually implemented using hash tables (Hash Table) or trees (Tree).
Example: in Python, classes are stored in __dict__ (a dictionary, analogous to a hash table).
Used to store pointers to virtual methods of classes in languages with polymorphism (C++, Java).
Implemented using arrays (Array) or trees (Tree).
Class objects are created on the heap (Heap) if they are created using new (C++, Java) or malloc (C).
Management can be handled using lists (Linked List) or trees (Tree) to optimize memory allocation.
In interpreted languages (Python, JavaScript), classes are stored in dictionaries (Hash Table/Dictionary).
Allows the structure of a class to be changed dynamically at runtime.
| Language | Where are classes stored? | Structure used |
|---|---|---|
| Python | __dict__ inside the class | Dictionary (Hash Table) |
| Java | Heap, ClassLoader | Tree, Array |
| C++ | VTable, static/heap | Array, Tree |
| JavaScript | Prototype chain | Objects (Hash Table) |
| C# | Managed by the CLR (Common Language Runtime), objects on the heap (Heap) | Tree, Hash Table |
| PHP | Symbol table, class array (class_table) in memory | Hash Table |
C# (C-Sharp)
All classes are managed by the CLR, which stores metainformation in trees (Tree) and hash tables (Hash Table).
Objects are created on the heap (Heap) if it is a reference type.
Static classes are stored in a separate memory area accessible to the whole application.
PHP
In PHP, classes are stored in a special hash table (class_table), and methods in function_table.
Each loaded class corresponds to an associative array holding its properties and methods.
Thanks to this mechanism, PHP supports dynamic creation and modification of classes at runtime.
Comments