Recall that an interface is made up of a set of signatures, which in turn are made up of an operation’s name, the objects that it accepts as parameters, and its return values. The interface represents the entire set of requests that are sent to the interface. For example, by typing an interface, that is, Type IFCE, the interface accepts all requests for operations defined in that interface. Two objects representing the type can share individual parts of an interface. In addition, interfaces can contain other interfaces, referred to as subsets. Frequently, we can refer to a subtype as inheriting from its supertype interface.
Interfaces are fundamental to object-oriented programming. An interface represents an abstract concept by declaring its intentions, but never reveals the how. In essence, the interface says nothing about its implementation. This is a win-win situation for developers. They can mutually share the same interface and write totally unique implementations without conflict, as long as they adhere to the interface’s signature.
Interfaces support dynamic binding for disparate objects sharing the same signature. For example, developers can submit a request to an object with confidence, knowing it will accept the request because it supports object substitutability. One object containing the same interface is interchangeable with another object at runtime, courtesy of a mechanism called polymorphism. As long as the object’s signature is adhered to, the object will process any request with equanimity.
During component-based development, you construct the interface so a client invocation on a specified service will never know how the request is implemented. Encapsulation shields the implementation from the client. Therefore, you can think of an interface as having two parts:
Interface Defines a set of public method signatures but provides no implementations
Published interface A uniquely identifiable interface made available through a registry to clients for dynamic discovery
Interfaces declared in Java or managed C++ typically provide only method signatures. Therefore, they describe why but not how the interface should be implemented. This allows for multiple implementations and allows services or components to enhance both flexibility and scalability. However, the stateless Internet environment does not guarantee that the interface’s implementation is always secure and compliant with any behavioral specification. Despite this limitation, businesses are gravitating toward more service-oriented systems. Perhaps it is possible to adhere to the safe practice of defining a behavioral interface.
Objects are created by instantiating a class. This process allocates storage for the object’s internal data consisting of instance variables. This in turn binds the object with its variable types. By employing a methodology called class inheritance, the subclass inherits all parent data type definitions and its behavioral characteristics. This means objects will perform operations defined in both the parent and child classes.
The sole purpose of an abstract class is to define a common interface for its child subclasses. However, an instance of this class can never be instantiated. Operations defined by an abstract class are called abstract operations, whereas classes that are not declared as abstract are called concrete classes. Abstract classes describe general behavioral characteristics, whereas concrete classes define more specific operations on an interface’s signature.
It is important to distinguish between an object’s class and its type. A class defines an object’s internal state and provides information on how to implement it. For example, superclass Employer is inheritable by several subclass employee types. A salaried employee defines its implementation in reference to class Employer. An employee retained on commission defines its behavior in reference to class Employer, and so on. In essence, class inheritance is just a mechanism for implementing and extending a specified class’s functionality. To be a bit banal, a child inherits all genetic characteristics from his/her parents, but extends the parents’ genetic and social inclinations by building on them and becoming an individual person. Interface inheritance reduces implementation dependencies between subsystems and components. Therefore, it is safe to assume that programming to an interface is better than programming to an implementation. Best practices suggest it is better to declare variables that are instances of an abstract class rather than instances of a concrete class.
In conclusion, perhaps one of the most important concepts is learning how to design reusable components. In addition, knowing how to implement abstract interfaces is essential to designing web-based applications in ASP.NET. Remember, the .NET Framework and the ASP.NET runtime are composed of reusable components and interfaces. Therein lies the key to understanding .NET and ASP.NET.