Your choices boil down to this: if a function needs data, that data must:
- be passed to the function as a parameter, or
- be in a place where the function can effectively query for it.
(I'll ignore 3. or be generated by the function itself.)
If you want to pass A::member
, you have several options. You can put the data in a context object and pass it around (this can be effective if you have a handful of these members that you want to pass around, and happens to works well in the presence of unit tests). You can pass the data directly into the function. You can pass the data to something that will in turn pass it to the function. You can use message passing. You can use more indirect mechanisms like publish/subscribe queues. You can choose how much knowledge such intermediaries have about the type of data they are passing. All of these imply various kinds of coupling between the source, transport, and destination as you pass the data from one place to another. At best this coupling can be irritating at scale; at worst this can be a serious design or security flaw.
If you want to put A::member
somewhere where it can be queried, you also have several options. A global variable is one. A data store that can be accessed (e.g. a file, a database, a service, a cache, an HTTP resource) is another. Each of these has implications: you need to consider who can access the data and how. If access is easy (like in global variables) you have the problem of how to evolve your system without breaking clients of your data. You may also have problems when it comes time to test your code. At best this coupling can be irritating at scale; at worst it can be a serious design flaw and lead to practically untestable code.
If you'd like to pass the data, but you don't like the number of places you need to pass it to, your other angle of attack is to limit the number of functions that need your data. I.e. consolidate your code so that fewer pieces of code actually need to know about A::member
. Various patterns like Facade, Bridge, Observer, and Abstract Base Class may help you at the language level. Architectural patterns such as Publish-Subscribe and Callback may also be able to help. Research the topics of decoupling, refactoring, and dependency elimination for inspiration.
So which of these is the right way? There is no one right way. You'll need to look at your particular case, weigh the options and tradeoffs for that case, and pick the one you like best.