0

The problem:

For simplicity i'll use a simple example. In a sample application, a Class-A reads some data.

Class-A then instantiates Class-B, which then instantiates Class-C. So in all there is a 3-level-hierarchy of classes A --> B --> C

Class B creates & manages custom objects based on the data found in class A. I have simply passed that data from class-A to class-B in the form of function/method parameters.

Class C, however, is different. It has 2 functions/methods that give it its data.

  1. firstMethod(arg) - which gives it data to work with. (called on class-B)
  2. otherMethod(otherArg) - with gives it other data to work with.

It was instanced by Class-B and the data that it needs from Class-B will be passed to it passed to by class-B through firstMethod(arg1). However, there is another data set that class-C needs to run properly. This other parameter has nothing to do with class-B; Therefore it would seem wrong to pass this information through this classes as a parameter to get to class-C.

How can I get this information from class-A to class-C without using class-B? What I did was create a Singleton class-S.

Class-S has defined within it the methods/functions (not variables) of class-A. After setting it up, Class-C can now call its otherMethod(otherArg) on Class-S which calls the needed function and returns the needed data directly from class A.

A-->B-->C
^       |
|___S___|

The Questions:

I've listed some of the problems of singletons ive seen around the net.

  1. From this link, They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell. [my edit] - While class-S is being used as a global instance, Class-c has its dependencies clearly defined. The methods/functions that's needed for it to work is defined in its interface.
  2. from this link, They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases. [my edit] is this setup still tightly coupling class-C with the singleton? If Class-C is to be unit tested, the singleton is not needed (at least i don't think so). Since the functions are clearly defined a mock class can fake its data.
  3. They carry state around for the lifetime of the application. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other. [my edit] Given the setup I'm not sure this will be a problem?

Any pointers on this will help much. Please no hate.. I googled but didn't find many definitive answers. Thanks. Any thoughts?

[My Edit] --> A comment below asked the following question that i thought important enough to add here.

Why don't you want to pass the additional data to B? If this data is needed to execute the command [in class-C], then it should be a parameter. Regardless if B uses it directly or passes it on

The Answer would be that this is a simple example using A, B, & C. The truth is the app is much more complex. Class-B is a reusable class that is used in many other parts of the app. If I made class-B accept the additional data as a parameter to pass to class-C, then in every other part of the app where class-B is used, I would have to pass nil for that parameter. Also, if class B is used in more places in the application: B->C...B->X...B->Y...B->Z ... etc, then the reusable class-B would now have to carry around the parameters of C, X, Y and Z.. or more. Class-B is a class that can instance classes of different types, but it does not know the information about the Classes it is has instanced/allocated. Its job is simply to instance/allocate a class, give the instanced-class the general information it needs via parameters and finally do some additional setup. But class-B should not know of the other specific data of its instanced classes. So it would not know that class-C needs to go to class-A to get its information. Only class-C would know where to get its specific information.

Just a coder
  • 15,480
  • 16
  • 85
  • 138
  • Why don't you want to pass the additional data to `B`? If this data is needed to execute the command, then it should be a parameter. Regardless if `B` uses it directly or passes it on. – Nico Schertler Oct 17 '15 at 11:53
  • @NicoSchertler I have edited the question to add your comment because i thought it was a good question. – Just a coder Oct 17 '15 at 20:36
  • Ok. Your description is still very general. I think it would help a lot if you could add a concrete example. I'm quite sure that a singleton is a bad idea. Maybe, B should pass C back to A and A could add the necessary data? – Nico Schertler Oct 17 '15 at 20:47
  • This is the concrete example. Class-B is a class that can spawn classes of different types, but it does not know the information about the Classes it is spawns. Its job is simply to spawn a class, give the spawned-class the general information it needs via parameters and finally do some additional setup. But class-B should not know of the other specific data of its class spawns. So it would not know that class-C needs to go to class-A to get its information. Only class-C would know where to get its specific information. So is singleton ok here?.. sorta? – Just a coder Oct 17 '15 at 20:51
  • To give more information about the app, It an app that reads data files/database/plist and converts that information into script files. One class reads the chunk of the data. The data is broken up into different parts and is given to the classes that need them. The classes then display the information as needed. Just like reading from a database no one class needs all of the information. – Just a coder Oct 17 '15 at 21:08
  • Perhaps the hierarchy should be `A --> C --> B` or perhaps `B` should be decoupled from `A` and `C`. Basically, it sounds like the hierarchy isn't right. – jaco0646 Oct 17 '15 at 22:56
  • @jaco0646 in the example, the App displays a hierarchy of data. Let's say Class-A reads the first data chunk and sends some data down the hierarchy. Class-B shows the mainview of the data, and class-C shows a detailed view of Class-B's data. It isnt possible to show the detailed view (class-C) before the mainView (class-B). But, the problem is that Class-C needs other data from class-A that wasnt passed through class-B. It shouldnt be passed to class-B because B is a re-usable class that can be used anywhere in the app to load any datareader's data (Explained in the [my edit] section above) – Just a coder Oct 18 '15 at 07:31
  • 1
    As an aside, the use of the phrase "code smell" is a good indication that someone is trying to elevate their own stylistic choices to the level of pseudo-science. **Anything** can be labelled that way with no need for evidence and the hipsters of the coding world will join as a chorus in denouncing it. – Phillip Mills Oct 18 '15 at 13:13
  • @PhillipMills, are you suggesting that Kent Beck (who coined the term) and Martin Fowler (who popularized it) were peddling pseudoscience? – jaco0646 Oct 19 '15 at 20:17

1 Answers1

1

I am bit loss with the concept of "spawn classes".

You said that C has member (i.e. is it a service class?),then let's say that C is called Cook and it has a single member called

  Cake bakeACakeMethod(Flour,Chocolate)

where Chocolate is the B class that you are talking about.

Since you want to skip the B class and use A class (Pineapple) straight in C, then you could change the method to

  Cake bakeACakeMethod(Flour,IYummy)

Where IYummy is an interface and A a B class implements IYummy, so the method allows both classes.

Other way to do it is to use overloading

magallanes
  • 6,583
  • 4
  • 54
  • 55
  • spawning a class meant creating a new class instance. Class-(B) follows factory pattern here: https://en.wikipedia.org/wiki/Factory_%28object-oriented_programming%29 . Its a reusable class that creates other classes. So class-(A) reads initial data, and instantiates (B). (B) then instantiates an appropriate class based on data passed to it from (A). It instantiates (C) and passes general-data to it. Class A, B, & C are totally separate classes (no inheritance/subclassing involved). Therefore (C) cant call method on (A) unless it has some reference to (A). I used singleton to get reference(A) – Just a coder Oct 18 '15 at 21:09
  • I have also edited the question above removing the words "spawned" and replaced it with "instanced" class – Just a coder Oct 18 '15 at 22:00