Backend Development 15 min read

Applying the Open‑Closed Principle and Bitmask Design for Extensible System Architecture

The article explains the six SOLID design principles, emphasizes the importance of the Open‑Closed principle, and demonstrates how to achieve extensible database schemas and APIs using type fields, extendable JSON columns, bitmap role encoding, and strategy/template patterns with concrete Java code examples.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Applying the Open‑Closed Principle and Bitmask Design for Extensible System Architecture

Six Design Principles

The author lists the six SOLID principles—Single Responsibility, Liskov Substitution, Dependency Inversion, Interface Segregation, Law of Demeter, and Open‑Closed—stating that the Open‑Closed principle is the most important because it underpins system extensibility.

Database Dimension

Design Type Fields

Add two columns biz_type and biz_sub_type to isolate large business categories and sub‑categories, allowing future expansion without schema changes.

Design Extend Fields

Add three nullable columns extend1 , extend2 , extend3 to store JSON‑encoded flexible data such as order, product, or marketing extensions.

Design Business Binary Field

Introduce a user_flag column that stores role information as a bitmap, enabling multiple roles per user with a single integer value.

id

name

super

admin

normal

101

用户一

1

0

0

102

用户二

0

1

0

103

用户三

0

0

1

104

用户四

1

1

1

Using a bitmap, the same data can be represented as decimal values 4, 2, 1, and 7 respectively.

Solution – Bitmap Method

Define each role as a single bit (1, 2, 4) and store the combined value in user_flag . The following Java enum shows the bit‑shift definition:

/**
 * User role enumeration
 */
public enum UserRoleEnum {
    // 1 -> 00000001
    NORMAL(1, "普通用户"),
    // 2 -> 00000010
    MANAGER(1 << 1, "管理员"),
    // 4 -> 00000100
    SUPER(1 << 2, "超级管理员");
    private int code;
    private String description;
    private UserRoleEnum(int code, String description) {
        this.code = code;
        this.description = description;
    }
    public String getDescription() { return description; }
    public int getCode() { return code; }
}

Utility methods for adding, removing, and checking roles use bitwise OR, XOR, and AND operations respectively:

public static Integer addRole(Integer oldRole, Integer addRole) {
    return oldRole | addRole;
}
public static Integer removeRole(Integer oldRole, Integer delRole) {
    return oldRole ^ delRole;
}
public static boolean hasRole(Integer allRole, Integer qryRole) {
    return (allRole & qryRole) == qryRole;
}

SQL examples show how to query users with a specific role using the bitmap column.

Interface Dimension

Design Typed Parameters

Use explicit fields such as bizType and bizSubType in DTOs to match the database type columns.

Design Loose Parameters

Alternatively, use a Map for flexible, loosely‑typed parameters.

Design API Versioning

Expose versioned URLs like /order/1.0/createOrder and /order/1.1/createOrder so old and new versions can coexist.

Vertical and Horizontal Design

Vertical dimension separates strategies (discount, logistics, refund) using the Strategy pattern. Horizontal dimension composes these strategies per order type using the Template Method pattern.

Strategy Interfaces and Implementations

public interface DiscountStrategy { void discount(OrderBO orderBO); }
@Component public class TypeADiscountStrategy implements DiscountStrategy { public void discount(OrderBO o){ o.setPrice(o.getPrice()*0.9); } }
@Component public class TypeBDiscountStrategy implements DiscountStrategy { public void discount(OrderBO o){ o.setPrice(o.getPrice()*0.8); } }
@Component public class TypeCDiscountStrategy implements DiscountStrategy { public void discount(OrderBO o){ o.setPrice(o.getPrice()*0.7); } }

A factory registers each strategy by order type code, and an executor retrieves and runs the appropriate strategy.

Template Method for Order Creation

public abstract class AbstractCreateOrderFlow {
    public void createOrder(OrderBO orderBO) {
        // validation
        // discount
        discount(orderBO);
        // weighing
        weighing(orderBO);
        // refund support
        supportRefund(orderBO);
        // persist
    }
    protected abstract void discount(OrderBO orderBO);
    protected abstract void weighing(OrderBO orderBO);
    protected abstract void supportRefund(OrderBO orderBO);
}

The concrete CreateOrderFlow injects executors for each step and delegates the work.

Conclusion

The article presents seven concrete techniques—type fields, extend fields, bitmap fields, typed parameters, loose parameters, API versioning, and vertical/horizontal design—to improve system extensibility.

Final Note

The author encourages readers to like, share, and follow the public account for more technical content.

design patternsStrategy PatternBackend DevelopmentDatabase Designtemplate methodopen-closed principlebitmask
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.