By utilizing Document Class it is much easier to make extension to the method by calling super(), and not having to always overwrite the entire function.
In ERPNext, most functions, whitelisted or not, behave this way. AFAIK, if the function is outside of class, only way to change its behavier is to monkey patch and overwrite the entire function make Frappe Framework not very snappy. And so far, it is quite painful especially more than one app is modifying same function.
In Frappe/ERPNext, a significant number of functions are written as standalone functions instead of being methods inside classes. The reasons for that would be simplicity and modularity as many functions are designed to be reusable across different contexts without being tightly coupled to a specific class. This also considered easier for functional testing.
More over, many whitelisted functions are meant to be called from the front end (through API calls) or via hooks, and writing them outside of a class makes it easier to expose them for direct use without requiring an instance of a class.
Frappe heavily relies on doc_events in hooks. This allows developers to hook into these events and execute custom logic without needing to override methods. This approach offers flexibility, but at the cost of requiring manual management of multiple hooks if many apps modify the same event.
Before this question, I did made the PR trying to extend the base functionality using class inheritance but I also got the answer from @blaggacao to use hook.
Based on your answer and from David, I would say the answer is a Design Pattern of ERPNext (chosen way to do things).
Extension is preferred to be hooks. And the hook points is not something fixed, it can be added more to make extension easier as in examples the above PR.