Ideally you would want to make as few calls to the blockchain as possible, as it is slow and would not make for a very active orderbook. The general rule of thumb for Ethereum (for now) is that the fewer transactions/calls you can make, the better.
With that said, one of the best ways to do this would be to build out your own block explorer, and talk to that with the front-end rather than reading from the blockchain. By having all the data stored in a local DB, you are able to hook up the front end of your exchange to this database and get much more efficiency than you would reading directly from the Ethereum network.
In terms of the list above, you can use whatever would serve your application best. If your decentralized exchange is well written and logs all relevant information, using events is a good way to go. You can also save the state of the entire contract in variables that you read from as well. Any of these options will work, and they will work best if used in a traditional database.
Imagine a scenario where you have multiple concurrent users. If you did everything on the blockchain (no other backend for data), each of these users would have to make X calls to the chain, effectively taking seconds to fully render the page they are on.