Dependency Injection vs. Global/Static data

T

thomas

Hi,

----injection---
class Util{
public:
void print(){...}
};

class Work{
void SetUtil(Util* pUtil){m_pUtil = pUtil;}
Util* m_pUtil;
};
----end----

----static----
class Util{
public:
static void print(){...}
};
 
V

Vladimir Jovic

thomas said:
Hi,

----injection---
class Util{

this class is missing base to use it in dependency injection
public:
void print(){...}
};

class Work{
void SetUtil(Util* pUtil){m_pUtil = pUtil;}
Util* m_pUtil;
};
----end----

----static----
class Util{
public:
static void print(){...}
};
----------
What's the advantages/disadvantages when comparing these two methods?
When I use these two methods in dll interface(Work class inside dll;
Util may be used by several modules.), anything I need to take special
care of?

The 1st method gives you flexibility, while the second is fixed. If you
provide a base class for Util class, you can easily use another
implementation later on, and switch between two
 
A

Alf P. Steinbach /Usenet

* thomas, on 02.09.2010 10:14:
----injection---
class Util{
public:
void print(){...}
};

class Work{
void SetUtil(Util* pUtil){m_pUtil = pUtil;}
Util* m_pUtil;
};
----end----

----static----
class Util{
public:
static void print(){...}
};

There is no polymorphism for either design.

In the first example you have the option of turning off and on printing. This
could much more easily be accomplished via a boolean member in 'Work' + an
internal print method that checks the boolean.

If you meant for 'print' to be virtual, then the first example offers the
additional functionality of customizing the effect of 'print'.

Presumably you know that, and whatever advantage depends on your requirements,
which you fail to state here. However, if the second example is a possible
solution for your requirements, then there is no current advantage, only a
possible future advantage. And in that case it's purely a methodology question,
"Should one design for possible future requirements?", and off-topic here.

C++ aspect: for the second example, use a namespace, not a class.

When I use these two methods in dll interface(Work class inside dll;
Util may be used by several modules.), anything I need to take special
care of?

That's a Windows question, not a C++ question.


Cheers & hth.,

- Alf
 
T

thomas

I should have provided more information.
-----base class---
struct IUtil{
virtual void print(){}
};
----end-----

----injection---
class Util : public IUtil{
public:
void print(){...}
};

class Work{
void SetUtil(IUtil* pUtil){m_pUtil = pUtil;}
IUtil* m_pUtil;
};
----end----

----static----
class Util{
public:
static IUtil* s_pUtil;
};
IUtil* Util::s_pUtil = NULL; //Util::s_pUtil = pUtil; (do assignment
somewhere else.)
 
G

Goran Pusic

I should have provided more information.
-----base class---
struct IUtil{
    virtual void print(){}};

----end-----

----injection---
class Util : public IUtil{
public:
    void print(){...}

};

class Work{
    void SetUtil(IUtil* pUtil){m_pUtil = pUtil;}
    IUtil*  m_pUtil;};

----end----

----static----
class Util{
public:
    static IUtil* s_pUtil;};

IUtil* Util::s_pUtil = NULL; //Util::s_pUtil = pUtil; (do assignment
somewhere else.)
----------

From the above code you can see that both provides flexibility. The
only difference is the implementation methods.
So any essential difference?

I'll presume that Work class has e.g. this:

void Work::work() {... m_pUtil->print(); ...}

If all instances of Work should use same Util, then clearly m_pUtil is
overkill. If not, then it isn't. But we don't know any of that, so we
can't tell you. It is very hard to guess these things, and it is very
hard to predict the future.

If, for example, at this stage, you use one Util for all Work-s, but
think that you might need separate ones later, you can do e.g.:

class Work
{
....
Util* GetUtil() { return GetGlobalUtil(); }
....
};

and not use m_pUtil anymore. Then, once you realize that you do want
several Util-s, just add your SetUtil and change GetUtil to:

Util* GetUtil() { return m_pUtil; }

That way, you get simpler design, no runtime cost, and the ability to
change later with less actual code changes.

Goran.
 
T

thomas

Thanks. Hm.. sorry for bad expression.

I want to print debug messages and hope that I can change output
destination according to different requirements.
There're two ways: dependency injection; static/global instances.
I think "static/global instances[method II] is enough, but I wonder
whether there's anything bad to my design I don't know.

-----Monitor class---
struct IMonitor{
virtual void print(){}
};
class Monitor : public IMonitor{
public:
void print(){...}
};
----end-----

[method I]
----injection---
class Work{
void SetMonitor(IMonitor* pMonitor){m_pMonitor = pMonitor;}
IMonitor* m_pMonitor;
};
----end----
To print messages, call "m_pMonitor->print()"

[method II]
----static----
class Util{
public:
static IMonitor* s_pMonitor;
};

IMonitor* Util::s_pMonitor = NULL; //Util::s_pMonitor = pMonitor; (do
assignment
somewhere else.)
-------end-----
To print messages, call "Util::s_pMonitor->print()"
 
P

Pavel

thomas said:
Thanks. Hm.. sorry for bad expression.

I want to print debug messages and hope that I can change output
destination according to different requirements.
There're two ways: dependency injection; static/global instances.
I think "static/global instances[method II] is enough, but I wonder
whether there's anything bad to my design I don't know.

-----Monitor class---
struct IMonitor{
virtual void print(){}
};
class Monitor : public IMonitor{
public:
void print(){...}
};
----end-----

[method I]
----injection---
class Work{
void SetMonitor(IMonitor* pMonitor){m_pMonitor = pMonitor;}
IMonitor* m_pMonitor;
};
----end----
To print messages, call "m_pMonitor->print()"

[method II]
----static----
class Util{
public:
static IMonitor* s_pMonitor;
};

IMonitor* Util::s_pMonitor = NULL; //Util::s_pMonitor = pMonitor; (do
assignment
somewhere else.)
-------end-----
To print messages, call "Util::s_pMonitor->print()"
If it were not for debugging, I would say the first snippet has
advantages of flexibility, easier adoption to multi-tasking (Monostates
are notoriously difficult to deal with in multi-threaded environment,
and dynamic libraries are not helping).

The second is simpler to implement, less intrusive to the existing
classes, slightly faster at run-time, takes no memory in the object,
easier to control as an "aspect" (e.g. turn printing on or off
on-the-fly or via compilation macro).

As it is for debugging, 2nd method seems to be more appropriate. I would
not even hesitate to use a macro like UTIL_PRINT() to make sure I can
remove this code from the binary at compilation time w/o an issue.

-Pavel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top