DRY stands for “don’t repeat yourself” meaning don’t write duplicate code but instead abstract common blocks of code that is used by different functions or classes into one place.
This can be variables, methods, or classes. If you hard code a variable in more than one place, abstract it to a public final constant variable. If you are using a same logic in more than one place, abstract it to a method. The same thing can be done for classes.
DRY Advantages
DRY Disadvantages
What not to do
* Don’t combine anything which uses similar code but not related. In other words don’t create a common variable or method for two different functionalities or things. For example a method that validates a bank account is also used to validate social security numbers. Down the road you might change this method because a bank account is different but that might cause social security number validation to crash.
2. Encapsulation
Encapsulate code that is expected to change in the future.
To encapsulate your code make your variables private and provide getters and setters to access and change them.
3. Open Closed Design Principle
Methods and classes should be open for extension when adding a new functionality and closed for modification.
This prevents developers from modifying already tested and working code which lessens the chance of breaking the existing code.
Changes are required when new functionality is added or existing functionality is updated. Often in both situations you will need to modify the existing code. You should avoid changing the existing code when requirements change. Instead you should extend the existing functionality by adding new code to meet the new requirements.
Use polymorphism and inheritance to extend the existing behavior. Use interface and abstract classes/methods to accomplish this.
Let’s say we a accounting system where we need to validate payment methods before adding or updating them.
public interface PaymentMethodValidator{ public boolean validate(); } public class CardValidator implements PaymentMethodValidator{ public boolean validate(){ // validate card payment method } } public class BankAccountValidator implements PaymentMethodValidator{ public boolean validate(){ // validate bank payment method } } // if you need to add more payment method validator like one for Apple pay then just implement PaymentMethodValidator
4. Single Responsibility Principle
A method or class should only have a single functionality which reduces coupling of different components. One reason for a class to change. Methods related to the same concern should be in one class.
A robust system is one that can handle these unwanted situations elegantly. There are various ways for a software engineer to achieve robustness, such as testing the code for different kinds of inputs, but generally, in order to achieve robustness (and high cohesion), programmers follow a certain set of rules and principles for better organization of object-oriented programs. One such principle is the single responsibility principle
If you put more than one functionality in a class. There is a chance you will break the existing functionality if you make changes to one of the functionality.
A typical violation of the single responsibility principle I often see in legacy Spring applications is an abundance of code in controller actions. I’ve seen Spring controllers getting JDBC connections to make calls to the database. This is a clear violation of the single responsibility principle. Controller objects have no business interacting with the database. Nor do controllers have any business implementing other business logic. In practice your controller methods should be very simple and light. Database calls and other business logic belong in a service layer
5. Dependency Inversion Principle
The beauty of this design principle is that any class which is injected by DI framework is easy to test with the mock object and easier to maintain because object creation code is centralized in the framework and client code is not littered with that.
Creating an object with the new operator makes it tightly coupled to another class.
6. Composition over Inheritance
Composition is more flexible in terms of what you want to do. With inheritance you might have to implement all methods from the super class. But with Composition you can have a type and then decide at run time whether you want to use it or not.
Another advantage of Composition is that you can have multiple types in one class but with inheritance you can only inherit one class.
Composition is easier to test because you can mock types.
7. Liskov Substitution Principle
Sub-types must be able to substitute in for super-types. If a super sub-type has more methods or functionality then there is a problem there.
8. Interface Segregation Principle
Interfaces with one method.
9. Programming for interface not implementation
You should use interface types for variables, method return types, or method parameters instead of subclass.
So instead of using ArrayList, use List.
10. Delegation Principle
Don’t do everything yourself. Use a dedicated class.