In programming, we generally have two types of objects; those that deal with data, and those that deal with algorithms. We are definitely advised to use SOLID in Salesforce, but it has nothing to do with the static-ness of a method.
For example, let's look at a standard library, Math.
Single responsibility principle
Math only deals with doing math-y type stuff. It doesn't manipulate strings, or parse Integers, or anything else. It has one responsibility: to expose mathematical algorithms.
It's a standard library, so it's closed. If we need a whole new set of algorithms, we can write our own math library. It would clearly be a Bad Idea if we could modify the system library.
Liskov substitution principle
Does not apply to Math, because it has no subclasses. It does only one thing, and that's the Math-y stuff it does.
Interface segregation principle
This is a specific interface. It does math, and that's it, and each method is clearly defined for specific cases (e.g. handling Decimal versus Integer).
Dependency inversion principle
There's no dependencies here, so it's not even relevant.
Now, you're saying, "but what about my classes?" And the answer is the same. Each class should do one thing and do it well. We're told to avoid the use of "god" classes, and best practices state that we should keep each class as small as possible, for maintenance reasons.
There's different types of classes we use in Salesforce, including Visualforce Controllers, Lightning Controllers, Web Service classes, Rest Resource classes, Schedulable classes, and so on. Most everything that you do will be dictated by the standard APIs laid out for you.
A general rule of thumb is that if you have a choice, you should consider if any data is encapsulated in the class. If there is no data (or, at least, no client-specific data), methods should be static. All Math functions fall in this category. For classes where there is data being operated on (i.e.
this actually means something useful), then the methods would not be static.
Also note that you can certainly use interfaces, that's a feature of the Dependency Inversion Principle. In fact, we use them all the time without really thinking about it. System.schedule, Database.executeBatch, System.enqueueJob, etc are all things we can only do with DIP in play. And you're definitely encouraged to do the same in your own code. Write interfaces, use existing interfaces, etc.
Without actually trying to sample how many methods out there seem to "violate" DIP as you understand it, realistically, that number is probably 1. I can think of a single case where it seems odd to construct an object that isn't used for data.
Going back to Math for a second, which code looks right to you?
Decimal d1 = Math.round(12.5);
Decimal d2 = new Math().round(12.5);
The methods that are static are static because they make sense. They don't deal with data, they only implement algorithms. Even going by SOLID and TDD, etc, you'll find that it's often not necessary to mock or extend anything, or block of parts of code with Test.isRunningTest or TestVisible, etc.
Testing is about verifying output, and well-written code can generally do so using only its public interfaces. If it can't, I would consider that code suspect and probably in violation of best practices.
An E2E test does not care about how something got from point A to point B, only that it does. The next layer of testing, the service layer, doesn't care about the UI tests, it cares only that the services provided are working. Finally, unit tests don't care about the service layer or the E2E tests; it only cares about what's going on at this level.
There's a reason why it's the test pyramid, the lower tests support the upper tests. The upper tests are only there to care about the entire thing moving as one large unit, but the pieces inside are all black boxes. The lower unit tests verify their little small corner of the world without caring about what happens in the bigger world.