Object Oriented Programming and Design Patterns Flashcards
What is the purpose of the Pillars of Object Oriented Programming? (i.e. what is the end goal of these pillars?)
The purpose of the Pillars of Object Oriented Programming (Encapsulation, Polymorphism, Abstraction, Inheritance) is to provide a framework for developing software systems that are robust, reliable, and maintainable. The end goal is to create secure programs that are modular, reusable, and extensible.
Encapsulation helps to hide the complexity of the internal workings of a system and provides a secure boundary around data and code. This ensures that the system is protected from unwanted access, modification, or corruption, and helps to maintain data integrity.
Polymorphism enables different objects to be treated as if they were the same type of object, allowing for greater flexibility and reusability. This also makes it easier to add new functionality to a system without having to modify existing code.
Abstraction provides a way to represent complex systems in a simplified manner, making it easier to understand and work with. It allows for the separation of concerns, enabling developers to focus on specific aspects of the system without being bogged down by irrelevant details.
Inheritance allows for the reuse of code by creating new classes that inherit the properties and behaviors of existing classes. This promotes code reuse, reduces redundancy, and helps to create a modular system that is easier to maintain and extend.
By applying these pillars of Object Oriented Programming, developers can create software systems that are more secure, maintainable, and adaptable to changing requirements.
What is Inheritance?
Inheritance is a fundamental concept in object-oriented programming that allows a class to inherit properties and behaviors from another class, referred to as the parent or base class. The class that inherits these properties and behaviors is called the child or derived class.
Inheritance enables developers to create new classes that are built upon existing classes, without having to re-implement the functionality that already exists in the base class. This can save significant time and effort in developing and maintaining code, and also promotes code reuse.
When a child class inherits from a parent class, it gains access to all of the parent class’s public and protected methods and properties. The child class can then override or extend these methods and properties, or add new ones of its own.
Inheritance is typically used to model real-world relationships between objects, such as a car class that inherits from a vehicle class, or a mammal class that inherits from an animal class. By using inheritance, developers can create a hierarchy of classes that accurately reflects the relationships between objects in the real world, making the code more intuitive and easier to understand.
What is Polymorphism?
Polymorphism is a core concept in object-oriented programming that allows objects of different classes to be treated as if they were the same type of object. It enables developers to write code that can work with objects of multiple classes, without having to know the specific type of object that is being worked with.
Polymorphism can take several forms, including method overloading, method overriding, and interfaces. Method overloading enables developers to define multiple methods with the same name but different parameter types, while method overriding allows a child class to provide its own implementation of a method that is already defined in the parent class.
Interfaces provide a way to define a set of methods that must be implemented by any class that implements the interface, regardless of its specific type. This allows for greater flexibility and modularity in code design, as it allows developers to define behavior without specifying a particular implementation.
Polymorphism is a powerful tool for creating reusable, modular code that can be easily extended and maintained. It enables developers to write code that is more flexible, easier to read and understand, and less error-prone.
What is Encapsulation?
Encapsulation is a key concept in object-oriented programming that involves hiding the internal details of a class from the outside world, and exposing only the necessary information through well-defined interfaces. Encapsulation provides a secure boundary around data and code, ensuring that the system is protected from unwanted access, modification, or corruption.
Encapsulation is achieved through the use of access modifiers such as private, public, and protected, which control the visibility of class members. Private members are only accessible within the class itself, while public members can be accessed by any code that has access to the object. Protected members are similar to private members, but can also be accessed by subclasses.
Encapsulation provides a number of benefits, including improved security, easier maintenance and testing, and better code organization. By hiding the implementation details of a class, developers can change the internal workings of a class without affecting the external code that uses it, making it easier to maintain and extend. Encapsulation also makes it easier to test code, as it allows for more fine-grained control over the inputs and outputs of a class.
Overall, encapsulation is a critical aspect of object-oriented programming that enables developers to create more secure, modular, and maintainable code. It is an essential tool for designing and implementing software systems that are both reliable and robust.
What is Abstraction?
Abstraction is a key concept in object-oriented programming that involves representing complex systems in a simplified manner. It provides a way to focus on the essential aspects of a system, while hiding unnecessary details.
In programming, abstraction is achieved through the use of abstract classes and interfaces. Abstract classes are classes that cannot be instantiated directly, and are typically used as base classes for other classes. Interfaces define a set of methods that must be implemented by any class that implements the interface.
Abstraction provides several benefits, including improved code organization, better code reuse, and easier maintenance. By abstracting away unnecessary details, developers can create code that is easier to read, understand, and modify. This makes it easier to maintain and extend software systems over time, as changes to the underlying code are less likely to have unexpected side effects.
Abstraction is also useful for promoting code reuse, as it allows developers to create modular, reusable code that can be used in a variety of contexts. This reduces redundancy and can lead to more efficient and reliable software systems.
Overall, abstraction is a powerful tool for creating software systems that are both simpler and more flexible. By focusing on the essential aspects of a system and hiding unnecessary details, developers can create code that is more robust, maintainable, and adaptable to changing requirements.
What is the keyword super?
The keyword “super” is a fundamental concept in object-oriented programming that is used to refer to the parent class of a subclass. It provides a way for a subclass to access and invoke methods and variables of its parent class, allowing for more flexible and powerful class hierarchies.
When a class extends another class, it inherits all of the public and protected methods and variables of the parent class. In cases where the subclass needs to override a method or variable from the parent class, it can use the “super” keyword to call the corresponding method or variable from the parent class.
The “super” keyword is typically used in the context of method overriding, where a subclass provides its own implementation of a method that is already defined in the parent class. By calling the parent class’s implementation of the method using “super”, the subclass can extend or modify the behavior of the parent class’s method while still retaining its original functionality.
The “super” keyword can also be used to invoke the constructor of the parent class from within the subclass’s constructor. This is useful in cases where the subclass needs to perform some additional initialization that builds upon the parent class’s initialization.
Overall, the “super” keyword is an important tool for creating flexible and powerful class hierarchies in object-oriented programming. It enables developers to extend and modify the behavior of existing classes in a way that is both intuitive and maintainable.
Describe method overriding and method overloading
Method overriding and method overloading are both important concepts in object-oriented programming that enable developers to create flexible and extensible code.
Method overriding is the process of defining a method in a subclass that has the same name, return type, and parameters as a method in its parent class. When the method is called on an instance of the subclass, the subclass’s implementation of the method is used instead of the parent class’s implementation.
Method overriding is typically used when the subclass needs to provide a different implementation of a method that is already defined in the parent class. This allows the subclass to customize the behavior of the method without having to modify the parent class.
Method overloading, on the other hand, is the process of defining multiple methods in the same class with the same name but different parameter lists. This allows the methods to be differentiated based on the number, types, or order of their parameters.
Method overloading is typically used when a class needs to provide multiple versions of the same method with different parameter types or configurations. This can improve the flexibility and readability of the code, as it allows developers to use a single method name for multiple related functions.
In summary, method overriding is used when a subclass needs to provide its own implementation of a method that is already defined in the parent class, while method overloading is used when a class needs to define multiple versions of the same method with different parameter types or configurations. Both concepts are important tools for creating flexible and extensible code in object-oriented programming.
What does it mean to ‘cast objects’ (a.k.a. covariance)?
Casting objects, also known as covariance, is a fundamental concept in object-oriented programming that involves converting an object of one type into an object of another related type. This process is sometimes necessary when working with polymorphic objects or when implementing inheritance hierarchies.
Casting can be achieved in two ways: upcasting and downcasting. Upcasting involves converting an object of a subclass into an object of its parent class. This is done implicitly by the compiler and is always safe, as the subclass is guaranteed to have all of the same methods and variables as its parent class. Downcasting, on the other hand, involves converting an object of a parent class into an object of a subclass. This is done explicitly using the cast operator and can be unsafe, as the parent class may not have all of the same methods and variables as its subclass.
Casting is useful in many contexts, including when working with collections of polymorphic objects, when implementing inheritance hierarchies, and when implementing generic algorithms that work with objects of different types.
Overall, casting objects is an important tool for working with polymorphic objects and implementing inheritance hierarchies in object-oriented programming. By allowing objects of related types to be treated interchangeably, casting enables developers to create more flexible and powerful software systems. However, care must be taken when downcasting, as it can lead to runtime errors if not done correctly.
Describe the java access modifiers and levels
In Java, access modifiers are keywords that are used to set the level of access to classes, methods, and variables. There are four access modifiers in Java: public, protected, private, and default (also known as package-private).
Public: The public access modifier is the least restrictive and allows access from anywhere in the program. When a class, method, or variable is declared as public, it can be accessed from any other class or package.
Protected: The protected access modifier allows access within the same package and by subclasses in other packages. When a class, method, or variable is declared as protected, it can be accessed by any class within the same package, as well as any subclass of the class in a different package.
Private: The private access modifier is the most restrictive and only allows access within the same class. When a class member is declared as private, it can only be accessed within the same class and cannot be accessed by any other class or package.
Default/Package-private: The default access modifier is used when no access modifier is specified. When a class, method, or variable is declared as default, it can be accessed by any other class within the same package, but cannot be accessed by classes in other packages.
Overall, access modifiers are an important part of Java’s encapsulation mechanism and are used to control the visibility and accessibility of classes, methods, and variables. By setting the appropriate access level, developers can ensure that their code is secure, maintainable, and follows best practices for object-oriented programming.
What are the differences between an abstract class and an interface?
Abstract classes and interfaces are both important tools in Java for creating reusable, extensible code. While they share some similarities, there are also some important differences between them.
One key difference is that abstract classes can have both abstract and non-abstract methods, while interfaces can only have abstract methods. This means that abstract classes can provide some implementation details, whereas interfaces cannot.
Another difference is that a class can implement multiple interfaces, but can only extend one abstract class. This means that interfaces are more flexible than abstract classes when it comes to implementing multiple behaviors or features.
Abstract classes can also have constructors, whereas interfaces cannot. This allows abstract classes to initialize member variables and perform other setup tasks, which can be useful in certain situations.
One advantage of interfaces is that they can be used to define contracts or agreements between classes, without specifying any implementation details. This allows classes to be more decoupled and easier to maintain, as changes to one class do not affect other classes that use the interface.
Overall, the choice between using an abstract class or an interface depends on the specific requirements of the code being developed. Abstract classes are useful when there are shared implementation details among related classes, while interfaces are useful when defining contracts or agreements between classes that are decoupled from their implementation.
What are the implicit modifiers for interface variables / methods?
In Java, there are implicit modifiers that apply to interface variables and methods. These modifiers are automatically applied and cannot be explicitly specified by the developer.
For interface variables, the implicit modifier is “public static final”. This means that all interface variables are public, static, and final by default. They are always accessible from other classes, cannot be changed once they are set, and can be accessed without instantiating the interface.
For interface methods, the implicit modifier is “public abstract”. This means that all interface methods are public and abstract by default. They are always accessible from other classes, but do not have a default implementation. Instead, any class that implements the interface must provide its own implementation of the interface methods.
Overall, the implicit modifiers for interface variables and methods ensure that interfaces are always accessible and have a consistent structure, regardless of how they are used in different parts of the program.
What is the difference between extends and implements?
In Java, both “extends” and “implements” are used to establish a relationship between classes, but they are used in different contexts.
“Extends” is used to create a subclass or a derived class that inherits all the properties and behaviors of the parent or super class. This means that the derived class can use all the non-private members of the parent class, including fields, methods, and nested classes. “Extends” is typically used with concrete or abstract classes, but not with interfaces.
“On the other hand, “implements” is used to indicate that a class is adopting a particular interface and will provide an implementation for all the methods declared in that interface. This means that the implementing class must provide a definition for all the methods declared in the interface. This is required to ensure that the implementing class can be used interchangeably with any other class that implements the same interface, regardless of its specific implementation details.
Overall, the difference between “extends” and “implements” is that “extends” is used to create a subclass that inherits from a parent class, while “implements” is used to indicate that a class is adopting a specific interface and providing an implementation for its methods.
Why was the default keyword introduced for interfaces?
The “default” keyword was introduced for interfaces in Java 8 as a means of allowing interfaces to have concrete method implementations. Prior to Java 8, interfaces could only declare abstract methods, which meant that any class that implemented an interface had to provide its own implementation for all the methods declared in the interface.
However, there were cases where it would be useful for interfaces to provide default behavior for certain methods, without requiring implementing classes to provide their own implementation. For example, imagine an interface with a dozen methods, where most of the methods have a common implementation, but a few of the methods need to be customized for specific use cases. Without the “default” keyword, every class that implemented the interface would need to provide its own implementation of all the methods, even the ones with the common implementation.
With the “default” keyword, an interface can provide a default implementation for a method, which can be overridden by classes that need to customize the behavior of that method. This allows interfaces to provide a more flexible and modular structure, while still allowing for customization when needed.
Overall, the “default” keyword was introduced for interfaces to provide a more efficient and modular way of providing default behavior for certain methods, without requiring implementing classes to provide their own implementation for every method declared in the interface.
What is a Singleton?
In software engineering, a Singleton is a design pattern that restricts the instantiation of a class to one object. This means that only one instance of the class can be created throughout the lifetime of an application, and this instance can be accessed from anywhere in the application.
The Singleton pattern is typically used to ensure that there is only one instance of a particular class, which can be used to manage global resources or shared states. This can be useful in scenarios where multiple objects need to access the same resource, but creating multiple instances of the resource would be wasteful or problematic.
To implement the Singleton pattern, the class should have a private constructor to prevent other classes from creating new instances of the class, and a public static method that returns the single instance of the class. The static method should also ensure that only one instance of the class is created, and return the existing instance if it has already been created.
It is important to note that while the Singleton pattern can be useful in certain scenarios, it can also lead to some issues such as tight coupling and difficulty with unit testing. Therefore, it is important to carefully consider the use case and potential drawbacks before implementing the Singleton pattern in an application.
What is a Factory?
In software engineering, a Factory is a design pattern that provides an interface for creating objects, but allows subclasses to decide which class to instantiate. The Factory pattern is used when we have a class hierarchy of related classes and we want to delegate the responsibility of object creation to one or more factory classes.
The Factory pattern consists of a Creator class that provides a factory method for creating objects, and a set of Product classes that define the objects that can be created by the Creator. The Creator class can be an abstract class or an interface, and it defines the factory method that subclasses must implement to create the Product objects. The Product classes are concrete classes that implement the functionality of the objects that can be created by the Creator.
One of the key benefits of using a Factory pattern is that it allows for more flexible object creation, since the decision about which object to create is made at runtime. This means that clients of the Factory don’t need to know which specific class they are instantiating, since the factory method will determine that at runtime based on the arguments provided.
Overall, the Factory pattern is a useful tool for managing object creation in complex applications, and can help to simplify code and make it more flexible and reusable. By abstracting away the details of object creation and allowing subclasses to determine the specific class to instantiate, the Factory pattern provides a modular and extensible way of managing object creation in an application.