Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've got a value that many objects need. For example, a financial application with different investments as objects, and most of them need the current interest rate.

I was hoping to encapsulate my "financial environment" as an object, with the interest rate as a property. But, sibling objects that need that value can't get to it.

So how do I share values among many objects without over-coupling my design? Obviously I'm thinking about this wrong.

share|improve this question
2  
Is the interest rate fixed for the duration of your calculations or are you doing something like a simulation where it can vary between timesteps? –  James Jul 9 '12 at 23:57
    
It is more like a simulation - it can change during the run. –  Greg Jul 10 '12 at 1:14
    
In that case does each investment really need to save the interest rate or can it receive it via a parameter to an update function that's called at each timestep? Can you post in pseudocode how your simulation operates? –  James Jul 10 '12 at 2:19
3  
You are one the correct track, a Singleton is a global with OO syntactic sugar on it and is a terrible solution that tightly couples your code in some of the worst ways possible. Read this article over and over until you understand it! –  Jarrod Roberson Jul 10 '12 at 3:10
    
Interest rate is like a Time Series which is a function that takes DateTime as input and return a number as output. –  rwong Jul 10 '12 at 4:17
show 4 more comments

9 Answers 9

up vote 14 down vote accepted

I've got a value that many objects need.

This is a design smell. It's uncommon that many objects need to know about something. That said, the current interest rate is a fairly good example of exceptional circumstances. One thing to worry about is that there's rarely the interest rate. Different financial instruments use different rates. At the very least, different locales use different 'standard' rates. Further, to aid in testing and reporting, you'll usually want to pass in a rate since you don't want to use the current rate there. You want to use the 'what if' or 'as of reporting date' rate.

So how do I share values among many objects without over-coupling my design?

By sharing them, not having them all refer to a single instance. Passing the same thing around is still coupling to a degree, but not over coupling since something like the current interest rate is needed as input to a variety of calculations.

share|improve this answer
15  
The problem with exceptional circumstances is that in real world software they are not that exceptional. –  mattnz Jul 10 '12 at 4:40
    
I think this is a serious misunderstanding. Our algorithms exist within different contexts simultaneously. The first is the global context. Then "this" context for object oriented languages. Session context in a web service, transaction context in a DB environment, Main window for a gui, ... and there are pieces of information that belong to these contexts. They must "hang around" and be available, the same set (objects) for anyone in the same context. This is okay. The problem is solving this for each object, not by creating a context service or using a framework, like Spring in Java. –  Lorand Kedves Jul 10 '12 at 12:41
3  
There is nothing exceptional about the current interest rate. There are many examples of the real world item having one value, - Open road Speed limit, acceptable blood alcohol level, GST (or VAT) tax rate to name a very few. That is the difference between Science and Engineering - Engineers solve today's real world problems, Scientists dream of the day the real world will fit into nice boxes of perfection and solve those problems. –  mattnz Jul 10 '12 at 21:52
    
I picked this as the answer because it's simple and doesn't rely on a decade of OOP experience to grok. MANY thanks to all the respondents. I had a full day of reading thanks to the many references but still remain a bit perplexed. For such a simple question, I was surprised at the variety of, and emotion behind, the responses. I remain convinced that sometimes there is a central source of global but varying data that is best served by a Singleton. I wouldn't think one should pass pointers up and down a hierarchy of objects just to avoid a Singleton. Thanks again everybody. –  Greg Jul 11 '12 at 10:34
    
@mattnz, the problem is that every single one of your examples is variable in cases where you distribute your program to multiple user bases which can span companies, states, or countries. All of them can also be variable over time. –  Dan Lyons Jul 11 '12 at 18:01
show 4 more comments

In this particular instance I would use the Singleton Pattern. The FinancialEnvironment would be the object all the other class libraries are aware of, but would be instantiated by the Singleton. Ideally you would then send that instantiated object to the various class libraries.

For example:

  • Service Layer (class library) - Instantiates the FinancialEnvironment object via a singleton
  • Business Logic Layer (class library) - Accepts the FinancialEnvironment object from the service layer
  • Data Access Layer (class library) - Accepts the FinancialEnvironment object from the service layer (or depending on your architecture the Business Logic Layer). Or maybe the Singleton invokes the Data Access Layer to get information, such as interest rate, from a repository (database/web service/WCF service) whatever.
  • Entities (or DTOs if you want to call it that) class library - Where the FinancialEnvironment object lives. All other class libraries have a reference to the Entities class library.

The other classes are only tied together through the Entities class library, they accept an instantiated FinancialEnvironment object. They don't care how it was created, only the service layer does, all they want is the information. The singleton could also be smart enough to store several FinancialEnvironment objects, depending on the rules for the local as @Telastyn pointed out.

On a side note, I am not a huge fan of the Singleton Pattern, I consider it a code smell, as it can be misused very easily. But in some cases you need it.

Update:

If you absolutely, positively must have a global variable then implementing the Singleton Pattern as described above would work. However, I am not a big fan of this, and based on the comments from my original post, several other people are not either. As something as volatile as a InterestRate, a Singleton may not be the best solution. Singletons work best when the information doesn't change. For example, I used a Singleton in one of my applications to instantiate performance counters. Because if they do change then you must have logic in place to handle the data being updated.

If I were a betting man I would bet the interest rate was stored somewhere in a database, or it was retrieved via a web service. In that case a Repository (data access layer) would be recommended to retrieve that information. To avoid unnecessary trips to the database (I am not sure how often interest rates change, or other information in the FinancialInformation class), caching could be used. In the C# world Microsoft's Caching Application Block library works very well.

The only thing that would change from the example above, would be the various classes in the service layer that need the FinancialInformation would retrieve from the Data Access Layer instead of the Singleton instantiating the object.

share|improve this answer
8  
Ugh. Making the global a singleton doesn't make it any less smelly. If anything you've restricted yourself that much more. –  Telastyn Jul 10 '12 at 0:38
3  
@DavidCowden it doesn't matter if they aren't complex to implement; they fubar your design worse than globals do. They're global and they enforce (unneeded) restriction that you only have one. –  Telastyn Jul 10 '12 at 1:06
4  
I was going to post a sarcastic comment sayin "make it a singleton and it will go from bad practice to best practice", but then I saw it was already an accepted and up voted answer. Very nice! –  Kevin Jul 10 '12 at 1:52
4  
Singleton is a global with OO syntactic sugar and a crutch for the lazy and weak minded. Singleton/global is the absolute worst way to tightly couple your code to something that will be a cancer later on when you realize what a colossally bad idea it was and why everyone says they are! –  Jarrod Roberson Jul 10 '12 at 3:07
4  
@Telastyn: Its an unfortunate reality that most perfect designs once they leave the perfectly ordered world of theoretical software design and join the real world, get fubar'd. –  mattnz Jul 10 '12 at 4:46
show 7 more comments

Configuration Files?

If you have values that are used "globally", please put them in a configuration file. Then each system and subsystem can reference this and pull the keys needed, make them read-only.

share|improve this answer
    
So you'd have the user update a configuration file every time the interest rate changes? –  Caleb Jul 10 '12 at 10:12
2  
Why not? depends on the "variable" of course things that change frequently should be placed inside a CENTRALISED datastore. –  Darknight Jul 10 '12 at 11:39
add comment

I'm speaking from the experience of one who has about a month of maintenance on a good sized (~50k LOC) project that we just released.

I can tell you that you probably don't really want a global object. Introducing that sort of cruft provides many more opportunities for abuse than it does help.

My initial suggestion is that if you have several different classes that need a current interest rate then you probably want to just have them implement an IInterestRateConsumer or something. Inside that interface you'll have a SetCurrentInterestRate(double rate) (or whatever makes sense), or maybe just a property.

Passing an interest rate around is not actually coupling - If your class needs an interest rate, that's part of its API. It's only coupling if one of your classes starts worrying about exactly how the other class uses that interest rate.

share|improve this answer
    
Passing an interest rate around is coupling, it just isn't bad coupling. –  Baqueta Jul 10 '12 at 7:36
add comment

Martin Fowler has an article that talks briefly about how to refactor a static global into something more flexible. Basically you make it into a singleton then modify the singleton so that it supports overriding the class of the instance with a subclass (and if needed move the logic that creates the instance to a separate class that can be sub-classed, which you would do if creating the super-class instance then replacing it later is a problem).

Of course, you have to weigh the problems with singletons (even substitutable singletons) vs. the pain of passing the same object everywhere.

As far as the "financial environment" object - it's convenient to program on the first pass, but when you are done you have added some extra dependencies. Classes that just need an interest rate now only function when passed a financial environment object, which will make them difficult to reuse when you don't happen to have a financial environment object lying about. So I would discourage passing it widely.

share|improve this answer
add comment

Why not put the interest rate data in a central cache?

You can use one of several cache libraries, whichever suits you requirements best, something like memcached solves all you concurrency and code management problems and will allow your application to scale to multiple processes.

Or go the whole hog and store them in a database, which will allow you to scale to multiple servers.

share|improve this answer
add comment

In such situations I have successfully introduced (reused) the "context" term with sometimes multiple layers.

This means a singleton, thus "global" object store, from which these kind of objects can be requested. Codes that require them, include the header of the store, and use the global functions to get their object instances (like now, the interest rate provider).

The store may be either:

  • strictly typed: you include the headers for all the served types and so you can create typed accessors, like InterestRate getCurrentInterestRate();
  • or generic: Object getObject(enum obType); and only extend the obType enum with the new kinds (obtypeCurrentInterestRate).

The bigger the system, the more usable the latter solution is, for a quite small risk of using the wrong enum. On the other hand, with languages that allow forward type declarations, I think you can use typed accessors without including all the headers in the store.

One more note: you may have multiple instances of the same object type for different uses, like sometimes different Language value for the GUI and for printout, global and session level logs, etc, so the enum / accessor name should NOT reflect the actual type, but the role of the requested instance (CurrentInterestRate).

In the store implementation, you have to manage the context levels and context instance collections. A simple example is web service, where you have the global context (one instance for all requests for that object - problematic when having a server farm), and a context for each web session. You can also have contexts for each user, who may have multiple, parallel sessions, etc. With multiple servers you should use a kind of distributed cache for such things.

When the request comes in, you decide which context level the requested object is, get that context for the call. If the object is there, you send it back; if not, you create and store it at that context level, and return it. Of course, synchronize the creation section (and publish it to the distributed cache). The creation can be configurable plugin-like, best with languages allowing creating object instances by their class name (Java, Objective C, ...), but you can do that in C as well with pluggable libraries having factory functions.

Side note: the caller should NOT know too much about its own contexts, and the requested object's context level. Reasons: 1: it is easy to make mistake (or "clever tricks") by playing with these parameters; 2: the context level of the requested might change later. I mostly connect context information to the thread, so the object store has the information without extra parameters from the request.

On the other hand, the request may contain hint for the instance: like getting interest rate for a specific date. It should be the same "global" access, but multiple instances depending on the date (and leading different date values to the same instance between rate changes), so it is advisable to add a "hint" object to the request, used by the instance factory and not the store; and a keyForHint to the factory, used by the store. You can add these functions later, I just mentioned.

For your case this is a kind of overkill (only one object is served in global level), but for a quite small and simple extra code right now, you get a mechanism for further, perhaps more complex requirements.

Another good news: if you are in Java, you get this service from Spring without thinking too much, I just wanted to explain it in details.

share|improve this answer
add comment

The reason NOT to use a global (or singleton) is that even though you initially expect to only have one value, it's often surprisingly useful to be able to use the same code multiple times in the same program, for instance:

  • to compute what WOULD happen if the interest rate was different
  • to have some components depend on the US interest rate and some components depend on the UK interest rate

I would make the interest rate a member of the "financial instrument" class, and accept that you have to pass it in to any member classses (either per-calculation, or giving them a pointer/hook to it on construction).

share|improve this answer
add comment

Things should be passed in messages, not read from a global thingy.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.