AAA Check - Yash-777/MyWorld GitHub Wiki
Factory vs Abstract Factory Pattern
Factory PatternIntent: One method, one product type β caller decides which variant via a parameter. |
Abstract Factory PatternIntent: A family of related objects β all created together, guaranteed to be compatible. |
|---|---|
// Product interface
class Button {
render() {}
}
class DarkButton extends Button {
render() { return "π€ Dark Button"; }
}
class LightButton extends Button {
render() { return "π€ Light Button"; }
}
class NightButton extends Button {
render() { return "π Night Button"; }
}
// Factory β creates ONE type of object based on input
class ButtonFactory {
static create(theme) {
switch (theme) {
case "dark": return new DarkButton();
case "light": return new LightButton();
case "night": return new NightButton();
default: throw new Error("Unknown theme");
}
}
}
// Usage
const btn = ButtonFactory.create("dark");
console.log(btn.render()); // π€ Dark Button |
// === Product Interfaces ===
// Buttons
class DarkButton { render() { return "π€ Dark Button"; } }
class LightButton { render() { return "π€ Light Button"; } }
class NightButton { render() { return "π Night Button"; } }
// Checkboxes
class DarkCheckbox { render() { return "π€ Dark Checkbox"; } }
class LightCheckbox { render() { return "π€ Light Checkbox"; } }
class NightCheckbox { render() { return "π Night Checkbox"; } }
// Modals
class DarkModal { render() { return "π€ Dark Modal"; } }
class LightModal { render() { return "π€ Light Modal"; } }
class NightModal { render() { return "π Night Modal"; } }
// === Abstract Factories (one per theme) ===
class DarkThemeFactory {
createButton() { return new DarkButton(); }
createCheckbox() { return new DarkCheckbox(); }
createModal() { return new DarkModal(); }
}
class LightThemeFactory {
createButton() { return new LightButton(); }
createCheckbox() { return new LightCheckbox(); }
createModal() { return new LightModal(); }
}
class NightThemeFactory {
createButton() { return new NightButton(); }
createCheckbox() { return new NightCheckbox(); }
createModal() { return new NightModal(); }
}
// === Factory Selector ===
function getThemeFactory(theme) {
switch (theme) {
case "dark": return new DarkThemeFactory();
case "light": return new LightThemeFactory();
case "night": return new NightThemeFactory();
default: throw new Error("Unknown theme");
}
}
// === Client Code ===
function buildUI(factory) {
const button = factory.createButton();
const checkbox = factory.createCheckbox();
const modal = factory.createModal();
console.log(button.render()); // π€ Dark Button
console.log(checkbox.render()); // π€ Dark Checkbox
console.log(modal.render()); // π€ Dark Modal
}
const factory = getThemeFactory("dark");
buildUI(factory); |
Builder Design Pattern
Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
| Lombok @Builder | Lombok generates code similar to this behind the scenes: |
|---|---|
Lombok's @Builder annotation automatically generates a static nested builder class, a builder() method,
and a build() method to create instances of the annotated class, reducing boilerplate code for the Builder design pattern.
It enables fluent API usage like Class.builder().field1(val).build().
Key Components of Generated Code
Static Inner Class: Creates ClassNameBuilder (e.g., PersonBuilder) to hold temporary state.
Builder Methods : Generates methods for each field, returning the builder instance for chaining.
build() Method : Contains the logic to call the actual class constructor, returning a new instance.
builder() Method : Creates a new instance of the builder class.
@Builder
public class User {
private String username;
private int age;
} |
public class User {
private String username;
private int age;
// Generated Constructor
User(String username, int age) {
this.username = username;
this.age = age;
}
// Generated Builder Method
public static UserBuilder builder() {
return new UserBuilder();
}
// Generated Static Inner Builder Class
public static class UserBuilder {
private String username;
private int age;
UserBuilder() {}
public UserBuilder username(String username) {
this.username = username;
return this;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(this.username, this.age);
}
}
} |
| Problem | Solution |
|---|---|
A complex object may require many values to initialize. Using a large constructor or setting values in different places makes the code confusing and difficult to manage.
For example, letβs think about how to create a House object. To build a simple house, you need to construct four walls and a floor, install a door,
fit a pair of windows, and build a roof. But what if you want a bigger, brighter house, with a backyard and other goodies
(like a heating system, plumbing, and electrical wiring)?
The constructor with lots of parameters has its downside: not all the parameters are needed at all times. In most cases most of the parameters will be unused, making the constructor calls pretty ugly. For instance, only a fraction of houses have swimming pools, so the parameters related to swimming pools will be useless nine times out of ten. |
The Builder pattern suggests that you extract the object construction code out of its own class and move it to separate objects called builders.
The Builder pattern lets you construct complex objects step by step. The Builder doesnβt allow other objects to access the product while itβs being built. The Builder pattern divides object creation into multiple steps (such as buildWalls, buildDoor, etc.).
To create an object, these steps are executed using a builder object.
You do not need to perform all the steps β only the steps required to create a specific version or configuration of the object are used. |
The instanceof pattern matching feature in Java was introduced to simplify type checking and casting. Instead of checking the type and then casting separately, you can do both in a single expression.
Before (traditional) instanceofJava required two steps: check + cast. |
After (Pattern Matching) for instanceof
|
|---|---|
β Check type : if (obj instanceof String)
β‘ Cast manually : String s = (String) obj;
β’ Use variable : System.out.println(s.length());
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.length());
} |
β Check + bind in one if (obj instanceof String s) : Safer casting
β‘ Use variable directly s is already in scope
β’ (no manual cast needed : Avoids ClassCastException)
// Introduced as a preview in Java 14 & 15 and officially released in Java 16.
if (obj instanceof String str) {
System.out.println(str.length());
}
// With newer Java versions (Java 17+), pattern matching works better with logical operators.
if (obj instanceof String s && s.length() > 5) {
System.out.println(s); // safe β both checks passed
} |
Mockito's
@MockAnnotation
Dates Date, LocalDate, OffsetDateTime
String dateStr = "2019-07-25";
Date parseDate = parseDate(dateStr, "yyyy-MM-dd"); // yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
System.out.println("Date :"+parseDate); // Thu Jul 25 00:00:00 IST 2019
System.out.println("LocalDate: "+getLocalDate(parseDate)); // 2019-07-25
System.out.println("OffsetDateTime: "+getOffsetDateTime(parseDate));// 2019-07-25T00:00+05:30public static Date parseDate(String dateStr, String datePattern) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat( datePattern );
Date date = dateFormat.parse(dateStr);
return date;
}
static ZoneId defaultZone = ZoneId.systemDefault(); // ZoneId.of("UTC");
public static LocalDate getLocalDate(Date dateTime) {
return dateTime.toInstant().atZone( defaultZone ).toLocalDate();
}
public static LocalDateTime getLocalDateTime(Date dateTime) {
return dateTime.toInstant().atZone( defaultZone ).toLocalDateTime();
}
public static OffsetDateTime getOffsetDateTime(Date dateTime) {
LocalDateTime localDateTime = getLocalDateTime(dateTime);
ZoneOffset offset = defaultZone.getRules().getOffset( localDateTime );
//return dateTime.toInstant().atOffset(offset);
return OffsetDateTime.of(localDateTime, offset);
}Rest APi Design Best Practices @SeleniumExpress pro tips