Builder pattern helps us create immutable class instances. Instances that you set their state once and don’t change it for the rest of the program. By not having setters and only initialize fields through constructors the object is immutable.
public User (String firstName, String lastName, int age, String phone){ } public User (String firstName, String lastName, String phone, String address){ } public User (String firstName, String lastName, int age){ } public User (String firstName, String lastName){ }
The problem is with this approach is that the number constructors to create can be too many to maintain properly. If we add setters we will lose immutability. This is where the Builder pattern comes into the picture.
How to implement:
public class User { private String firstName; private String lastName; private int age; private String phone; private User(UserBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; } //---- all getters no setters public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public static class UserBuilder { private String firstName; private String lastName; private int age; private String phone; private UserBuilder() {} public static UserBuilder standard() { return new UserBuilder(); } public static User defaultClient() { return new UserBuilder().build(); } public UserBuilder firstName(String firstName) { this.firstName = firstName; return this; } public UserBuilder lastName(String lastName) { this.lastName = lastName; return this; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phone(String phone) { this.phone = phone; return this; } public User build() { User user = new User(this); validateUserObject(user); return user; } // validate user object private void validateUserObject(User user) { } } }
Main class
public class BuilderMain { public static void main(String[] args) { User user = UserBuilder.standard() .age(12) .phone("3101234567") .firstName("Folau") .lastName("Kaveinga") .build(); System.out.println(ObjectUtils.toJson(user)); } }
Something developers need to keep track of is that when adding a new field to the immutable class it needs to be added to the builder as well.
Advantages
Disadvantages
Components are like functions that return HTML elements. Components are independent and reusable bits of code. They serve the same purpose as JavaScript functions, but work in isolation and returns HTML via a render function. Components come in two types, Class components and Function components, in this tutorial we will concentrate on Class components.
When creating a React component, the component’s name must start with an upper case letter. The component has to include the extends React.Component
statement, this statement creates an inheritance to React.Component, and gives your component access to React.Component’s functions. The component also requires a render()
method, this method returns HTML. A component must be exported.
class Home extends React.Component { render() { return <h2>Hello World!</h2>; } } export default Home;
Here is the same example as above, but created using a Function component instead. A Function component also returns HTML, and behaves pretty much the same way as a Class component, but Class components have some additions, and will be preferred in this tutorial.
function Home() { return <h2>Hello World!</h2>; }
function components are a simpler way to write components that only contain a render
method and don’t have their own state. Instead of defining a class which extends React.Component
, we can write a function that takes props
as input and returns what should be rendered. Function components are less tedious to write than classes, and many components can be expressed this way.
function Home(props) { return <h2>Hello {props.name}!</h2>; }
If there is a
function in your component, this function will be called when the component gets initiated. The constructor function is where you initiate the component’s properties. In React, component properties should be kept in an object called constructor()
state
.
You will learn more about state
later in this tutorial.
The constructor function is also where you honor the inheritance of the parent component by including the super()
statement, which executes the parent component’s constructor function, and your component has access to all the functions of the parent component (React.Component
).
class Home extends React.Component { constructor() { super(); this.state = {name: "Folau"}; } render() { return <h2>Hey this.state.name</h2>; } }
A good rule of thumb is that if a part of your UI is used several times (Button
, Panel
, Avatar
), or is complex enough on its own (App
, FeedStory
, Comment
), it is a good candidate to be extracted to a separate component.
All React components must act like pure functions with respect to their props.
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.
Singleton Pattern is used when you only need one instance of a class for an entire program. In most cases, you will provide global access to this singleton instance.
Variables within this instance can be modified from everywhere in the program which is the biggest problem with a singleton object. Serialization and Multithreading are the main two problems to deal with when it comes to singleton and luckily we have a solution which is using Enum.
There are other ways to create a singleton but this is the best and safest way to do it.
How to implement a singleton:
1. Create an Enum class as the singleton class. Enum is thread safe.
2. Make the default constructor private and make no other constructor and by doing this there will be no way for the class to be instantiated using the new keyword.
public enum EnumSingleton { INSTANCE; private Connection connection = null; private EnumSingleton() { System.out.println("Get new connection to mysql!"); try { String host = "localhost"; String port = "3306"; String dbName = "mysql_playground"; String username = "root"; String password = ""; connection = DriverManager.getConnection( "jdbc:mysql://" + host + ":" + port + "/" + dbName + "?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC", username, password); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public Connection getConnection() { return connection; } // add other logic }
public class SingletonMain { public static void main(String[] args) throws SQLException { // best way SingletonMain singletonMain = new SingletonMain(); singletonMain.getUsers(); // calling this method results in reusing the connection that // has been established already. We are using a singleton here. singletonMain.getUsers(); } public void getUsers() throws SQLException { Connection connection = EnumSingleton.INSTANCE.getConnection(); Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("select * from user"); while (rs.next()) { int id = rs.getInt("id"); int salary = rs.getInt("salary"); System.out.println("id: " + id + ", salary: " + salary); } } }
Uses