Loading ...
Sorry, an error occurred while loading the content.

RE: Monostates vs. Singletons (Was: Re: [XP] Singletons == Global s?)

Expand Messages
  • Glew, Andy
    By the way, Ryan King s example of refactoring a common prefix using a monostate leads, via a small extension to the example, to an almost perfect example of
    Message 1 of 27 , Mar 28, 2001
    • 0 Attachment
      By the way, Ryan King's example of refactoring a common
      prefix using a monostate leads, via a small extension
      to the example, to an almost perfect example of why
      both monostates and singletons smell bad: both are
      examples of globaals, a singleton a global variable,
      a monostate a global class.

      Ryan factored out setting a common prefix for log messages
      within a method:

      > method foo:
      > Logger logger = new Logger();
      > logger.log("foo: Bluzzle!");
      > logger.log("foo: Blazzle!");
      > logger.log("foo: Quuuxle!");

      into

      > method foo:
      > Logger logger = new Logger();
      > logger.setPrefixBeforeAllMessages("foo: ");
      > logger.log("Bluzzle!");
      > logger.log("Blazzle!");
      > logger.log("Quuuxle!");

      But, what if you don't just want a common prefix within
      a module? What if you want to set a common prefix
      for a method, and all of it's submethods - so that
      if method bar is called from foo, bar's log messages
      appear as

      foo/bar: Snixle!

      and so on?


      The monostate does not accomplish this.
      The monostate and the singleton are almost equivalently
      bad here.

      You could kluge it in for both monostate and singleton
      using class static members,
      not associated with individual instances, but
      it is not MP safe.
      Or, you could have the MP awareness live in the logger,
      and have it create global per-thread state.


      But if you pass the logger as a parameter,
      or embedded within a context object, the logger class
      need not be MP aware (at least not wrt prefixes),
      and yet the same effect could be achieved.


      ----

      Ryan's full original example:


      > What if we noticed something like the following (using a Monostate):
      >
      > method foo:
      > Logger logger = new Logger();
      > logger.log("foo: Bluzzle!");
      > logger.log("foo: Blazzle!");
      > logger.log("foo: Quuuxle!");
      >
      > method bar:
      > Logger logger = new Logger();
      > logger.log("bar: Snixle!");
      > logger.log("bar: Snaxle!");
      > logger.log("bar: Troxel!");
      >
      > The common prefixes ("foo: ", "bar: ") are repetitive and a low-level
      > stating of a higher-level intent, so let's refactor it:
      >
      > method foo:
      > Logger logger = new Logger();
      > logger.setPrefixBeforeAllMessages("foo: ");
      > logger.log("Bluzzle!");
      > logger.log("Blazzle!");
      > logger.log("Quuuxle!");
      >
      > method bar:
      > Logger logger = new Logger();
      > logger.setPrefixBeforeAllMessages("bar: ");
      > logger.log("Snixle!");
      > logger.log("Snaxle!");
      > logger.log("Troxel!");
      >
      > To accomplish this we can just toss in an instance variable
      > along with the
      > static variables.
    • azami@speakeasy.net
      ... What about a single logger supplier that by default provides access to a single instance. In addition, it can take an identifier for a logger; if said
      Message 2 of 27 , Mar 28, 2001
      • 0 Attachment
        --- In extremeprogramming@y..., "Glew, Andy" <andy.glew@i...> wrote:
        > Ryan factored out setting a common prefix for log messages
        > within a method:
        >
        > > method foo:
        > > Logger logger = new Logger();
        > > logger.log("foo: Bluzzle!");
        > > logger.log("foo: Blazzle!");
        > > logger.log("foo: Quuuxle!");
        >
        > into
        >
        > > method foo:
        > > Logger logger = new Logger();
        > > logger.setPrefixBeforeAllMessages("foo: ");
        > > logger.log("Bluzzle!");
        > > logger.log("Blazzle!");
        > > logger.log("Quuuxle!");
        >
        > But, what if you don't just want a common prefix within
        > a module? What if you want to set a common prefix
        > for a method, and all of it's submethods - so that
        > if method bar is called from foo, bar's log messages
        > appear as
        >
        > foo/bar: Snixle!
        >
        > and so on?
        >
        >
        > The monostate does not accomplish this.
        > The monostate and the singleton are almost equivalently
        > bad here.
        >
        > You could kluge it in for both monostate and singleton
        > using class static members,
        > not associated with individual instances, but
        > it is not MP safe.
        > Or, you could have the MP awareness live in the logger,
        > and have it create global per-thread state.
        >
        >
        > But if you pass the logger as a parameter,
        > or embedded within a context object, the logger class
        > need not be MP aware (at least not wrt prefixes),
        > and yet the same effect could be achieved.

        What about a single "logger supplier" that by default provides access
        to a single instance. In addition, it can take an identifier for a
        logger; if said logger already exists, the caller gets that instance,
        else the caller gets a new instance (which is then associated with the
        identifier).

        Code that wants to use the same logger just uses the same identifier.
        If necessary, the identifier could be passed around.

        If necessary (e.g. for testing code) the logger supplier could also
        offer some configuration capabilities, such as "for this identifier,
        supply this test stub logger".

        The logger supplier is still a singleton. The code that wants to log
        does not know or care whether anybody else is using the logger it is.
        (Perhaps there's an "unnamed" logger option? "I want a new logger,
        but _you_ tell me the identifier".)

        Just brain-dumping! :-)

        -Matthew
        azami@...
      • Eric Hodges
        ... Create a class that prepends a string before it logs something (using the monostate logger). Create an instance of that class in a method. That s easy.
        Message 3 of 27 , Mar 28, 2001
        • 0 Attachment
          > -----Original Message-----
          > From: Glew, Andy [mailto:andy.glew@...]
          > Sent: Wednesday, March 28, 2001 11:42 AM
          > To: 'extremeprogramming@yahoogroups.com'
          > Subject: RE: Monostates vs. Singletons (Was: Re: [XP] Singletons ==
          > Global s?)
          >
          >
          > By the way, Ryan King's example of refactoring a common
          > prefix using a monostate leads, via a small extension
          > to the example, to an almost perfect example of why
          > both monostates and singletons smell bad: both are
          > examples of globaals, a singleton a global variable,
          > a monostate a global class.
          >
          > Ryan factored out setting a common prefix for log messages
          > within a method:
          >
          > > method foo:
          > > Logger logger = new Logger();
          > > logger.log("foo: Bluzzle!");
          > > logger.log("foo: Blazzle!");
          > > logger.log("foo: Quuuxle!");
          >
          > into
          >
          > > method foo:
          > > Logger logger = new Logger();
          > > logger.setPrefixBeforeAllMessages("foo: ");
          > > logger.log("Bluzzle!");
          > > logger.log("Blazzle!");
          > > logger.log("Quuuxle!");
          >
          > But, what if you don't just want a common prefix within
          > a module? What if you want to set a common prefix
          > for a method, and all of it's submethods - so that
          > if method bar is called from foo, bar's log messages
          > appear as
          >
          > foo/bar: Snixle!
          >
          > and so on?

          Create a class that prepends a string before it logs something (using the
          monostate logger). Create an instance of that class in a method. That's
          easy.

          >
          >
          > The monostate does not accomplish this.

          Nope, but something else can.

          > The monostate and the singleton are almost equivalently
          > bad here.

          Why? Because you can't give them stack dependent behavior? Don't ask
          singletons to do things like that.

          >
          > You could kluge it in for both monostate and singleton
          > using class static members,
          > not associated with individual instances, but
          > it is not MP safe.
          > Or, you could have the MP awareness live in the logger,
          > and have it create global per-thread state.

          Military police?
        • Glew, Andy
          ... MultiProcessor safe. Also known as MultiThread safe. Your suggested solution - creating a prepending class - is either not MP safe, hides the MP awareness
          Message 4 of 27 , Mar 28, 2001
          • 0 Attachment
            > Create a class that prepends a string before it logs
            > something (using the monostate logger).
            > Create an instance of that class in a method. That's
            > easy.
            >
            > > it is not MP safe.
            >
            > Military police?


            MultiProcessor safe.
            Also known as MultiThread safe.

            Your suggested solution - creating a prepending class
            - is either not MP safe, hides the MP awareness in the
            class (creating per-thread state) ---- or, simply
            does not accomplish what I asked: to prepend a path
            to all called methods and functions, for the
            current thread.
          • Glew, Andy
            You ve got the gist of it!
            Message 5 of 27 , Mar 28, 2001
            • 0 Attachment
              You've got the gist of it!
            • Ryan King
              ... Actually, it wouldn t be particularly kludgey at all to do that. If you want prefixes to be accumulated you ll have to pass the Logger objects down in one
              Message 6 of 27 , Mar 28, 2001
              • 0 Attachment
                On Wed, Mar 28, 2001 at 09:41:50AM -0800, Glew, Andy wrote:
                > [...]
                > What if you want to set a common prefix for a method, and all of it's
                > submethods.
                > [...]

                Actually, it wouldn't be particularly kludgey at all to do that. If you
                want prefixes to be accumulated you'll have to pass the Logger objects
                down in one way or another, but we're used to that sort of thing. If you
                create a state in point A, and you want it to be there in point B, you
                have to give it a path between the two.

                You're right in saying that the Monostate doesn't solve that problem in
                any special way -- it also doesn't do your dishes, give you financial
                advice, or help you arrive at your appointments on time. ;)

                It *does*, however, give you the freedom to decrease its "globalness" as
                the need arises.

                In other words:

                Its advantage lies in the fact that you can turn turn it into
                something that is not purely a "Mono"-state whenever you want.

                If you need the behavior that would come from using the objects as a
                local variables (such as in the aforementioned examples), you just
                toss in some instance variables and keep going.

                If the indentation before those two statements does not convince you, I
                just don't know what will.

                - Ryan King
              • Eric Hodges
                ... Why doesn t it? You make an instance of my pre-pend class in a thread, only use it in that thread, and it will prepend text to your messages. Here s the
                Message 7 of 27 , Mar 28, 2001
                • 0 Attachment
                  > -----Original Message-----
                  > From: Glew, Andy [mailto:andy.glew@...]
                  > Sent: Wednesday, March 28, 2001 12:09 PM
                  > To: 'extremeprogramming@yahoogroups.com'
                  > Subject: RE: Monostates vs. Singletons (Was: Re: [XP] Singletons ==
                  > Global s?)
                  >
                  >
                  > > Create a class that prepends a string before it logs
                  > > something (using the monostate logger).
                  > > Create an instance of that class in a method. That's
                  > > easy.
                  > >
                  > > > it is not MP safe.
                  > >
                  > > Military police?
                  >
                  >
                  > MultiProcessor safe.
                  > Also known as MultiThread safe.
                  >
                  > Your suggested solution - creating a prepending class
                  > - is either not MP safe, hides the MP awareness in the
                  > class (creating per-thread state) ---- or, simply
                  > does not accomplish what I asked: to prepend a path
                  > to all called methods and functions, for the
                  > current thread.

                  Why doesn't it? You make an instance of my pre-pend class in a thread, only
                  use it in that thread, and it will prepend text to your messages.

                  Here's the class if it makes it more clear:

                  public class PrependedLogger {
                  private String prefix;
                  public PrependedLogger(String prefix) {
                  this.prefix = prefix;
                  }
                  public void log(String message) {
                  TheOneTrueLogger.log(prefix+message);
                  }
                  }

                  Use it in a method, all of your log messages will be prepended.

                  Maybe I don't understand the requirements.
                • Glew, Andy
                  ... Use it in a method, all of the log messagaes in that method will be prepended. If you want all of the log mssages for a method, and all of its callees, to
                  Message 8 of 27 , Mar 28, 2001
                  • 0 Attachment
                    > Why doesn't it? You make an instance of my pre-pend class in
                    > a thread, only
                    > use it in that thread, and it will prepend text to your messages.
                    >
                    > Use it in a method, all of your log messages will be prepended.
                    >
                    > Maybe I don't understand the requirements.

                    Use it in a method, all of the log messagaes in that
                    method will be prepended.

                    If you want all of the log mssages for a method,
                    and all of its callees, to be prepended, you either
                    have to pass the prepended logger object to all
                    of the callees - basically, a context object
                    - or you have to arrange so that each callee's
                    invocation of the singleton or monostate will
                    catch the PrependedLogger.
                    But, they already have TheOneTrueLogger
                    monostate or singleton wired into them.
                  • Glew, Andy
                    ... Right. When you pass it around, it s basically a context object. ... Sure. You can always edit the code to change the monostate or singleton into a
                    Message 9 of 27 , Mar 28, 2001
                    • 0 Attachment
                      > > What if you want to set a common prefix for a method, and
                      > > all of it's submethods.
                      >
                      > Actually, it wouldn't be particularly kludgey at all to do
                      > that. If you
                      > want prefixes to be accumulated you'll have to pass the Logger objects
                      > down in one way or another, but we're used to that sort of
                      > thing.

                      Right. When you pass it around, it's basically
                      a context object.



                      > It *does*, however, give you the freedom to decrease its
                      > "globalness" as the need arises.

                      Sure. You can always edit the code to change the monostate
                      or singleton into a context object.

                      Whereas, if you had used a context object in the first place,
                      you would not be needing to change the code.
                    • Eric Hodges
                      ... From: Glew, Andy To: Sent: Wednesday, March 28, 2001 10:51 PM Subject: RE: Monostates vs.
                      Message 10 of 27 , Mar 28, 2001
                      • 0 Attachment
                        ----- Original Message -----
                        From: "Glew, Andy" <andy.glew@...>
                        To: <extremeprogramming@yahoogroups.com>
                        Sent: Wednesday, March 28, 2001 10:51 PM
                        Subject: RE: Monostates vs. Singletons (Was: Re: [XP] Singletons == Global
                        s?)


                        > > Why doesn't it? You make an instance of my pre-pend class in
                        > > a thread, only
                        > > use it in that thread, and it will prepend text to your messages.
                        > >
                        > > Use it in a method, all of your log messages will be prepended.
                        > >
                        > > Maybe I don't understand the requirements.
                        >
                        > Use it in a method, all of the log messagaes in that
                        > method will be prepended.
                        >
                        > If you want all of the log mssages for a method,
                        > and all of its callees, to be prepended, you either
                        > have to pass the prepended logger object to all
                        > of the callees - basically, a context object

                        Yes, that's what I'm recommending. Don't use Singletons unless there is
                        just one of something. The Singleton here is the only logger. The
                        PrependedLoggers (or whatever I called them) have to go on the stack.

                        > - or you have to arrange so that each callee's
                        > invocation of the singleton or monostate will
                        > catch the PrependedLogger.
                        > But, they already have TheOneTrueLogger
                        > monostate or singleton wired into them.

                        Right, that's why you don't do that. Only use Singletons to represent
                        unique things.

                        I think what you folks are smelling are Singletons that ought to be
                        Multipletons. I just made that word up, but you get my drift. That's
                        definitely stinky. Anytime you find yourself thinking "Hey, I wish I had
                        one of these for every thread", refactor the Singleton into a factory or map
                        or something.
                      • Dinwiddie, George
                        ... I don t see this. My singletons are a class like any other class. It s just that I access them through a factory method instead of instantiating them
                        Message 11 of 27 , Mar 29, 2001
                        • 0 Attachment
                          > From: Ryan King [mailto:rking@...]
                          > Sent: Wednesday, March 28, 2001 11:52 AM
                          >
                          > On Tue, Mar 27, 2001 at 10:05:02AM -0500, Dinwiddie, George wrote:
                          > > It seems to me that the only difference (in Java) between Monostate
                          > > and Singleton is that the client code would be calling
                          > > new Logger().log(myMessage);
                          > > instead of
                          > > Logger.getInstance().log(myMessage);
                          > > I don't see this to be a significant advantage.
                          >
                          > IMHO, the first reads like prose and the second reads like someone dropped
                          > a box of words on the ground. But!, that's just preference -- the real
                          > reason is this:
                          >
                          > Consider it a violation of the LawOfDemeter. (I say as I duck the torrent
                          > of shoes being thrown at me for mentioning a programming "Law". Just
                          > pretend that I had said the "SmellOfDemeter" instead, which is how I treat
                          > it anyway.)
                          >
                          > The canonical rationale for said law is to avoid making objects aware of
                          > the structure of the objects they're calling.
                          >
                          > With Singletons, the knowledge of the fact that there is only one of them
                          > is forced onto the users of the class, making it harder to reverse.

                          I don't see this. My singletons are a class like any other class. It's
                          just that I access them through a factory method instead of instantiating
                          them with 'new'. I suppose you could say that using a factory causes you
                          to violate the Law of Demeter, since you then call methods on the returned
                          object.

                          Or is it the fact that I'm calling the factory method and the returned
                          object's method on the same line? I'm treating the factory method as
                          something that cannot fail. Would it be better to say
                          Logger myLogger = Logger.getInstance();
                          myLogger.log(myMessage);
                          Actually, there have been times when I've done something like that,
                          but it was when I intended to use the Logger a lot, rather than a
                          single time. Generally, I don't want to log THAT much stuff.


                          > When would you ever want to reverse this decision?
                          >
                          > Well, to phrase it generally, I would say that static members are a code
                          > smell (they're basically namespaced globals), and that with a Monostate
                          > you can easily and incrementally remove this smell.
                          >
                          > Let's use the Logger.log(message) example.
                          >
                          > What if we noticed something like the following (using a Monostate):
                          >
                          > method foo:
                          > Logger logger = new Logger();
                          > logger.log("foo: Bluzzle!");
                          > logger.log("foo: Blazzle!");
                          > logger.log("foo: Quuuxle!");
                          >
                          > method bar:
                          > Logger logger = new Logger();
                          > logger.log("bar: Snixle!");
                          > logger.log("bar: Snaxle!");
                          > logger.log("bar: Troxel!");
                          >
                          > The common prefixes ("foo: ", "bar: ") are repetitive and a low-level
                          > stating of a higher-level intent, so let's refactor it:
                          >
                          > method foo:
                          > Logger logger = new Logger();
                          > logger.setPrefixBeforeAllMessages("foo: ");
                          > logger.log("Bluzzle!");
                          > logger.log("Blazzle!");
                          > logger.log("Quuuxle!");
                          >
                          > method bar:
                          > Logger logger = new Logger();
                          > logger.setPrefixBeforeAllMessages("bar: ");
                          > logger.log("Snixle!");
                          > logger.log("Snaxle!");
                          > logger.log("Troxel!");
                          >
                          > To accomplish this we can just toss in an instance variable along with the
                          > static variables.
                          >
                          > Maybe I'm just missing something, but it seems to me that it would be a
                          > pain to accomplish the same effect with a Singleton.

                          Well, I wouldn't think of putting such state into the Logger. I treat it
                          as a facility that all the code can use, but none of them own it. If I'm
                          going to exercise control over the Logger's behavior, I'd set up a control
                          structure (GUI or otherwise) specific to it.

                          As for your example, I'd probably do something like:

                          public class MyClass {
                          Logger logger = Logger.getInstance();

                          private void log(String prefix, String message) {
                          logger.log(prefix+message);
                          }

                          public void foo() {
                          String logPrefix = "foo: ";
                          log(logPrefix, "Bluzzle!");
                          log(logPrefix, "Blazzle!");
                          log(logPrefix, "Quuuxle!");
                          }

                          public void bar() {
                          String logPrefix = "bar: ";
                          log(logPrefix, "Snixle!");
                          log(logPrefix, "Snaxle!");
                          log(logPrefix, "Troxel!");
                          }
                          }

                          Granted, you might be able to output the strings without concatenating
                          them into a new string if you do it in the Logger class, but I hope not
                          to be logging so much that the Logger is a performance bottleneck.


                          > > It's been years since I've done any C++, so I could be missing
                          > > something obvious, but in your example Config class, what prevents
                          > > two threads from initializing the class simultaneously?
                          >
                          > Nope, your C++ skillz aren't failing you: the example there is not
                          > multi-thread-aware. I didn't include mutexes, or even mention the
                          > threading issues for two reasons:
                          >
                          > 1) because of my bias against threads as being premature optimizations
                          > (See wiki?ThreadsConsideredHarmful).
                          >
                          > 2) The same tricks for making Singletons thread-safe apply to the
                          > Monostate. (Notice the similarities between the body of the Monostate
                          > constructor and the Singleton's getInstance() method -- they're
                          > effectively the same thing)
                          >
                          > > In that example, it bothers me that the constructor, in most cases,
                          > > isn't really a constructor. The fact that the various objects
                          > > share state but make it look as if they don't, well, that really
                          > > bothers me. I don't like my code to ever lie, even for convenience.
                          >
                          > It's not a "lie", it's more like an "omission of facts". =) If the
                          > Monostate is considered to be a liar, then consider any objects that
                          > encapsulate information to be likewise.
                          >
                          > I can see that you have some reservations, and I think what you need is
                          > this song:
                          >
                          > Lyle Lanley: Well, sir, there's nothing on earth
                          > Like a genuine,
                          > Bona fide,
                          > Electrified,
                          > Quick-start
                          > Monostate!
                          > What'd I say?
                          > Ned Flanders: Monostate!
                          > Lyle Lanley: What's it called?
                          > Patty+Selma: Monostate!
                          > Lyle Lanley: That's right! Monostate!
                          > [crowd chants `Monostate' softly and rhythmically]
                          > Miss Hoover: I hear those things are awfully coupled...
                          > Lyle Lanley: Without it, ma'am, your code's quadrupled!
                          > Apu: Could the class structure easily bend?
                          > Lyle Lanley: Of course it does, my Hindu friend!
                          > Barney: What about us Singleton slobs?
                          > Lyle Lanley: You'll be given cushy jobs!
                          > Abe: Were you sent here by the devil?
                          > Lyle Lanley: No, good sir, I'm on the level.
                          > Wiggum: The ring came off my pudding can.
                          > Lyle Lanley: Take my pen knife, my good man.
                          > I swear it's Springfield's only choice...
                          > Throw up your hands and raise your voice!
                          > All: Monostate!
                          > Lyle Lanley: What's it called?
                          > All: Monostate!
                          > Lyle Lanley: Once again...
                          > All: Monostate!
                          > Marge: But main() is still all cracked and broken...
                          > Bart: Sorry, Mom, the mob has spoken!
                          > All: Monostate!
                          > Monostate!
                          > Monostate!
                          > [big finish]
                          > Monostate!
                          > Homer: Mono... D'oh
                          >
                          > Hope this helps,
                          > - Ryan King
                          >

                          "On second thought, let's not go to Camelot. They are a silly lot." ;-)

                          - George
                        • Dinwiddie, George
                          ... YAGNI? Actually, all this discussion is making me much more at ease with my use of singletons. I d been worried about them being a code smell, but I
                          Message 12 of 27 , Mar 29, 2001
                          • 0 Attachment
                            > > It *does*, however, give you the freedom to decrease its
                            > > "globalness" as the need arises.
                            >
                            > Sure. You can always edit the code to change the monostate
                            > or singleton into a context object.
                            >
                            > Whereas, if you had used a context object in the first place,
                            > you would not be needing to change the code.

                            YAGNI? Actually, all this discussion is making me much more at
                            ease with my use of singletons. I'd been worried about them
                            being a code smell, but I think that, at least the use I make of
                            them, it's only a small and not particularly unpleasant one.

                            - George
                          • Glew, Andy
                            ... Exactly - this discussion has persuaded me that YAGNI applies to context object passing in general - global state, such as singletons, monostates, etc. are
                            Message 13 of 27 , Mar 29, 2001
                            • 0 Attachment
                              > > > It *does*, however, give you the freedom to decrease its
                              > > > "globalness" as the need arises.
                              > >
                              > > Sure. You can always edit the code to change the monostate
                              > > or singleton into a context object.
                              > >
                              > > Whereas, if you had used a context object in the first place,
                              > > you would not be needing to change the code.
                              >
                              > YAGNI? Actually, all this discussion is making me much more at
                              > ease with my use of singletons. I'd been worried about them
                              > being a code smell, but I think that, at least the use I make of
                              > them, it's only a small and not particularly unpleasant one.

                              Exactly - this discussion has persuaded me that YAGNI
                              applies to context object passing in general - global
                              state, such as singletons, monostates, etc. are acceptable,
                              up to the point that they are a problem, at which point the
                              refactoring into context object passing can be done.

                              The only reason to do context objects upfront is
                              the usual one of published interface. The later
                              emerging issue of desiring to change context
                              on a case by case is YAGNI until you need it,
                              and then refactor.

                              I wonder: why are singletons acceptable to YAGNI,
                              but global variables not? I think mainly that while
                              singletons are global state, they have a functional
                              or method interface, whereas raw access to global
                              variables is harder to refactor without changing
                              usages. Probably the Eiffel rule about data members
                              vs. functions should also apply here: any access to
                              a global variable should be syntactically indistinguishable
                              from method invocation.
                            • Ryan King
                              ... Normally, when you hear the LoD, you hear it like this (from http://www.enteract.com/~bradapp/docs/demeter-intro.html): A method of an object should
                              Message 14 of 27 , Apr 1, 2001
                              • 0 Attachment
                                On Thu, Mar 29, 2001 at 03:04:21PM -0500, Dinwiddie, George wrote:
                                > > Consider [Singletons to be] a violation of the LawOfDemeter. [...]
                                > >
                                > > The canonical rationale for said law is to avoid making objects aware of
                                > > the structure of the objects they're calling.
                                > >
                                > > With Singletons, the knowledge of the fact that there is only one of them
                                > > is forced onto the users of the class, making it harder to reverse.
                                >
                                > I don't see this. My singletons are a class like any other class. It's
                                > just that I access them through a factory method instead of instantiating
                                > them with 'new'. I suppose you could say that using a factory causes you
                                > to violate the Law of Demeter, since you then call methods on the returned
                                > object.

                                Normally, when you hear the LoD, you hear it like this (from
                                http://www.enteract.com/~bradapp/docs/demeter-intro.html):

                                "A method of an object should invoke only the the methods of the following
                                kinds of objects:

                                1. itself
                                2. its parameters
                                3. any objects it creates/instantiates
                                4. its direct component objects"

                                ...but if you stop there, then you are left without a handful of good
                                constructs such as factories (even simple ones like "Date::now()"), or
                                even memory allocation (ouch). However, in the paragraph below that list,
                                you'll see:

                                "If the "returned" object isn't a subpart of the object whose method was
                                invoked, nor of some other object, then it typically is not a violation of
                                LoD to invoke a method of the returned object (particularly if the object
                                was created by the invoking method)."

                                Wwhat I was getting at was that the member "SomeSingleton::instance_"
                                seems to me to be a subpart of "class SomeSingleton".

                                On the other hand, it is true that you could re-work the innards of "class
                                SomeSingleton" and "SomeSingleton::getInstance()" so that it can have
                                instance data, proving that the structure isn't known by the users of the
                                class.

                                I have two problems with that solution, though:

                                1) Now the code is definitely lying. "getInstance()" means
                                "getTheInstance()", but we're redefining it to mean "getAnInstance()".
                                What does the operator "new" mean but "getAnInstance()"? Why not use
                                it instead, even if there is incidentally only one?

                                2) On the practical side, it requires more thought and code to do the
                                necessary rewrite (as compared to a Monostate).

                                > Would it be better to say
                                > Logger myLogger = Logger.getInstance();

                                Maybe it would be less noisy, but that's not relevant to the comparison.
                                (Conversely, I don't really care if you use the Monostate with the "new
                                Logger().log(...)" notation)

                                > > When would you ever want to reverse this decision?
                                [snipped my questionable "common prefix" example answer to this question]

                                > Well, I wouldn't think of putting such state into the Logger. I treat it
                                > as a facility that all the code can use, but none of them own it.

                                I would at least think of it, because I the following is redundant:

                                > String logPrefix = "foo: ";
                                > log(logPrefix, [...]
                                > log(logPrefix, [...]
                                > log(logPrefix, [...]

                                The point here is: If you have an object that is a hybrid between class
                                data and instance data you will have a more difficult time if you're
                                starting with the Singleton pattern. I've always thought of static data
                                as smell, and it seems that the difficulty involved in creating instance
                                data discourages removal of this smell.

                                However, I can't easily think of any crisp examples[1] about when you'd
                                need this flexibility, so let's just assume the above is entirely
                                unfounded. ;)

                                Even if that is the case, it seems to me that the noisy "getInstance()"
                                calls serve no purpose... so why bother with them?

                                > > I can see that you have some reservations, and I think what you need is
                                > > this song: [...]
                                >
                                > "On second thought, let's not go to Camelot. They are a silly lot." ;-)

                                I have this terrible personality defect (among others): a selfish
                                appreciation for inside humor. That is, I love being the one on the
                                "inside", watching those on the "outside" squirm, but when the roles are
                                reversed I'll go to no end to get the person to explicitly spell out their
                                reference (thus destroying the nuance).

                                You're my next victim -- Where does that Camelot thing come from?

                                Later. =)
                                - Ryan King

                                [1] I'm starting to believe that the inability to come up with good
                                examples is an indication of either incomplete, incorrect, and/or
                                incommunicable thinking. In other words, I think it might be a
                                ThoughtSmell when an opinion is only true when spoken in generalities.
                              • azami@speakeasy.net
                                ... lot. ;-) ... Monty Python and the Holy Grail. And I believe the quote is, On second thought, let s not go to Camelot. Tis a silly place. -Matthew
                                Message 15 of 27 , Apr 2, 2001
                                • 0 Attachment
                                  --- In extremeprogramming@y..., Ryan King <rking@c...> wrote:
                                  > > "On second thought, let's not go to Camelot. They are a silly
                                  lot." ;-)
                                  > You're my next victim -- Where does that Camelot thing come from?

                                  Monty Python and the Holy Grail. And I believe the quote is, "On
                                  second thought, let's not go to Camelot. 'Tis a silly place."

                                  -Matthew
                                  azami@...
                                • Dinwiddie, George
                                  Thanks, I haven t seen that movie lately and I m starting to forget a few lines. - George I saw a doctor, once. E didn t see me. I was iding. From:
                                  Message 16 of 27 , Apr 2, 2001
                                  • 0 Attachment
                                    Thanks, I haven't seen that movie lately and I'm starting to forget
                                    a few lines.

                                    - George

                                    "I saw a doctor, once. 'E didn't see me. I was 'iding."


                                    From: azami@... [mailto:azami@...]
                                    > --- In extremeprogramming@y..., Ryan King <rking@c...> wrote:
                                    > > > "On second thought, let's not go to Camelot. They are a silly
                                    > lot." ;-)
                                    > > You're my next victim -- Where does that Camelot thing come from?
                                    >
                                    > Monty Python and the Holy Grail. And I believe the quote is, "On
                                    > second thought, let's not go to Camelot. 'Tis a silly place."
                                  • Dinwiddie, George
                                    ... I don t think that getInstance implies a singleton or not. ... eh??? ... it ... OK, putting the log prefix each time isn t a great solution. (I ll blame
                                    Message 17 of 27 , Apr 2, 2001
                                    • 0 Attachment
                                      > From: Ryan King [mailto:rking@...]

                                      > Wwhat I was getting at was that the member "SomeSingleton::instance_"
                                      > seems to me to be a subpart of "class SomeSingleton".
                                      >
                                      > On the other hand, it is true that you could re-work the innards of "class
                                      > SomeSingleton" and "SomeSingleton::getInstance()" so that it can have
                                      > instance data, proving that the structure isn't known by the users of the
                                      > class.
                                      >
                                      > I have two problems with that solution, though:
                                      >
                                      > 1) Now the code is definitely lying. "getInstance()" means
                                      > "getTheInstance()", but we're redefining it to mean "getAnInstance()".
                                      > What does the operator "new" mean but "getAnInstance()"? Why not use
                                      > it instead, even if there is incidentally only one?

                                      I don't think that getInstance implies a singleton or not.

                                      > 2) On the practical side, it requires more thought and code to do the
                                      > necessary rewrite (as compared to a Monostate).

                                      eh???

                                      > > Well, I wouldn't think of putting such state into the Logger. I treat
                                      it
                                      > > as a facility that all the code can use, but none of them own it.
                                      >
                                      > I would at least think of it, because I the following is redundant:
                                      >
                                      > > String logPrefix = "foo: ";
                                      > > log(logPrefix, [...]
                                      > > log(logPrefix, [...]
                                      > > log(logPrefix, [...]
                                      >
                                      > The point here is: If you have an object that is a hybrid between class
                                      > data and instance data you will have a more difficult time if you're
                                      > starting with the Singleton pattern. I've always thought of static data
                                      > as smell, and it seems that the difficulty involved in creating instance
                                      > data discourages removal of this smell.

                                      OK, putting the log prefix each time isn't a great solution. (I'll blame
                                      it on my invisible pair.)

                                      How about this. Let's say I start with a singleton class like this:

                                      public class Logger {
                                      private static Logger singleton = new Logger();
                                      private Logger() {
                                      }
                                      public void log(String message) {
                                      System.out.println(message);
                                      }
                                      public static Logger getInstance() {
                                      return singleton;
                                      }
                                      }

                                      Now, we want to add prefixes:

                                      public class Logger {
                                      private static final String emptyString = "";
                                      private String prefix;
                                      private static Map loggers = new HashMap();
                                      private Logger(String prefix) {
                                      loggers.put(prefix, this);
                                      }
                                      public void log(String message) {
                                      System.out.println(prefix+message);
                                      }
                                      public static Logger getInstance() {
                                      return getInstance(emptyString);
                                      }
                                      public static Logger getInstance(String prefix) {
                                      Logger instance;
                                      if (loggers.containsKey(prefix)) {
                                      instance = (Logger)loggers.get(prefix);
                                      } else {
                                      instance = new Logger(prefix);
                                      }
                                      return instance;
                                      }
                                      }

                                      Does this smell better?

                                      - George

                                      P.S. Thanks for this discussion. Currently I don't have anyone suitable
                                      for
                                      discussing code smells. Too many people here haven't developed a nose or
                                      think
                                      that "if it ain't broke, don't fix it." I need the feedback.
                                    • Eric Bennett
                                      ... Color me clueless. Why not just add a method public static void Log(String message) { getInstance().log( message ); } and call it with Logger.Log(
                                      Message 18 of 27 , Apr 2, 2001
                                      • 0 Attachment
                                        On Mon, 2 Apr 2001, Dinwiddie, George wrote:

                                        > public class Logger {
                                        > private static Logger singleton = new Logger();
                                        > private Logger() {
                                        > }
                                        > public void log(String message) {
                                        > System.out.println(message);
                                        > }
                                        > public static Logger getInstance() {
                                        > return singleton;
                                        > }
                                        > }

                                        Color me clueless. Why not just add a method

                                        public static void Log(String message) {
                                        getInstance().log( message );
                                        }

                                        and call it with Logger.Log( "lalala" );

                                        The getInstance/log combo doesn't tell you anything more about what state
                                        the logger maintains or what the intent is of keeping an instance of it.

                                        I fail to see how code which does logging via Logger.getInstance().log()
                                        could remain unmodified if you added prefixes or other semantics to the
                                        logger. Since you will have to refactor client code anyway might as well
                                        choose the simplest, prettiest option - which to me is Logger.Log().

                                        - Eric B.

                                        --
                                        "Actually I'm a Lumberjack, and I'm okay!"
                                      • Dinwiddie, George
                                        Good point. I thought of that possibility, but then thought that I d be more likely to collapse them into a single class, as shown, at least until I needed to
                                        Message 19 of 27 , Apr 2, 2001
                                        • 0 Attachment
                                          Good point. I thought of that possibility, but then thought that
                                          I'd be more likely to collapse them into a single class, as shown,
                                          at least until I needed to differentiate them. To me, it was an
                                          easier refactoring.

                                          I notice that your PrefixedLogger is quite different from your
                                          Logger.
                                          - It doesn't use a factory to create it.
                                          - It's not a derived class, so there's more work to convert
                                          calling code from Logger to PrefixedLogger.

                                          Since we don't have any actual client code, maybe this is ok.
                                          It kinda nags at me, though.

                                          - George

                                          -----Original Message-----
                                          From: Rex_Jolliff@... [mailto:Rex_Jolliff@...]

                                          Your solution seems to be doing two things in one, how about:

                                          public class Logger {
                                          private static Logger singleton = new Logger();
                                          private Logger() {
                                          }
                                          public void log(String message) {
                                          System.out.println(message);
                                          }
                                          public static Logger getInstance() {
                                          return singleton;
                                          }
                                          }

                                          public class PrefixedLogger {
                                          String Prefix;

                                          public PrefixedLogger (String aPrefix) {
                                          this.Prefix = aPrefix;
                                          }
                                          public void log (String aMessage) {
                                          Logger.getInstance ().log (this.Prefix + aMessage);
                                          }
                                          }





                                          "Dinwiddie, George" <George.Dinwiddie@...> on 04/02/2001 11:21:35
                                          AM

                                          Please respond to extremeprogramming@yahoogroups.com











                                          To: "'extremeprogramming@yahoogroups.com'"
                                          <extremeprogramming@yahoogroups.com>

                                          cc: (bcc: Rex Jolliff/YM/RWDOE)



                                          Subject: RE: Monostates vs. Singletons (Was: Re: [XP]
                                          Singletons == Global s?)





                                          Federal Record Status Not
                                          Determined




                                          > From: Ryan King [mailto:rking@...]

                                          > Wwhat I was getting at was that the member "SomeSingleton::instance_"
                                          > seems to me to be a subpart of "class SomeSingleton".
                                          >
                                          > On the other hand, it is true that you could re-work the innards of "class
                                          > SomeSingleton" and "SomeSingleton::getInstance()" so that it can have
                                          > instance data, proving that the structure isn't known by the users of the
                                          > class.
                                          >
                                          > I have two problems with that solution, though:
                                          >
                                          > 1) Now the code is definitely lying. "getInstance()" means
                                          > "getTheInstance()", but we're redefining it to mean "getAnInstance()".
                                          > What does the operator "new" mean but "getAnInstance()"? Why not use
                                          > it instead, even if there is incidentally only one?

                                          I don't think that getInstance implies a singleton or not.

                                          > 2) On the practical side, it requires more thought and code to do the
                                          > necessary rewrite (as compared to a Monostate).

                                          eh???

                                          > > Well, I wouldn't think of putting such state into the Logger. I treat
                                          it
                                          > > as a facility that all the code can use, but none of them own it.
                                          >
                                          > I would at least think of it, because I the following is redundant:
                                          >
                                          > > String logPrefix = "foo: ";
                                          > > log(logPrefix, [...]
                                          > > log(logPrefix, [...]
                                          > > log(logPrefix, [...]
                                          >
                                          > The point here is: If you have an object that is a hybrid between class
                                          > data and instance data you will have a more difficult time if you're
                                          > starting with the Singleton pattern. I've always thought of static data
                                          > as smell, and it seems that the difficulty involved in creating instance
                                          > data discourages removal of this smell.

                                          OK, putting the log prefix each time isn't a great solution. (I'll blame
                                          it on my invisible pair.)

                                          How about this. Let's say I start with a singleton class like this:

                                          public class Logger {
                                          private static Logger singleton = new Logger();
                                          private Logger() {
                                          }
                                          public void log(String message) {
                                          System.out.println(message);
                                          }
                                          public static Logger getInstance() {
                                          return singleton;
                                          }
                                          }

                                          Now, we want to add prefixes:

                                          public class Logger {
                                          private static final String emptyString = "";
                                          private String prefix;
                                          private static Map loggers = new HashMap();
                                          private Logger(String prefix) {
                                          loggers.put(prefix, this);
                                          }
                                          public void log(String message) {
                                          System.out.println(prefix+message);
                                          }
                                          public static Logger getInstance() {
                                          return getInstance(emptyString);
                                          }
                                          public static Logger getInstance(String prefix) {
                                          Logger instance;
                                          if (loggers.containsKey(prefix)) {
                                          instance = (Logger)loggers.get(prefix);
                                          } else {
                                          instance = new Logger(prefix);
                                          }
                                          return instance;
                                          }
                                          }

                                          Does this smell better?

                                          - George

                                          P.S. Thanks for this discussion. Currently I don't have anyone suitable
                                          for
                                          discussing code smells. Too many people here haven't developed a nose or
                                          think
                                          that "if it ain't broke, don't fix it." I need the feedback.


                                          To Post a message, send it to: extremeprogramming@...

                                          To Unsubscribe, send a blank message to:
                                          extremeprogramming-unsubscribe@...

                                          Don't miss XP UNIVERSE, the first US conference on XP and Agile Methods.
                                          Early
                                          registration discounts until April 10, 2001. www.xpuniverse.com for details
                                          and
                                          registration.

                                          Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/






                                          To Post a message, send it to: extremeprogramming@...

                                          To Unsubscribe, send a blank message to:
                                          extremeprogramming-unsubscribe@...

                                          Don't miss XP UNIVERSE, the first US conference on XP and Agile Methods.
                                          Early registration discounts until April 10, 2001. www.xpuniverse.com for
                                          details and registration.

                                          Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
                                        • Dinwiddie, George
                                          As my example showed, you *don t* have to change the client code if they don t require a prefix. As for your suggestion, if you re going to go that route, why
                                          Message 20 of 27 , Apr 2, 2001
                                          • 0 Attachment
                                            As my example showed, you *don't* have to change the
                                            client code if they don't require a prefix.

                                            As for your suggestion, if you're going to go that
                                            route, why not just condense it to

                                            public class Logger {
                                            public static void Log(String message) {
                                            System.out.println(message);
                                            }
                                            }

                                            In fact, the above is frequently my starting point in a program.
                                            It usually doesn't last very long, though, before I rip it out
                                            and replace it with something else. Maybe that's just prejudice
                                            on my part, however.

                                            Does a static method have more or less smell than a singleton
                                            accessed via a static factory method?

                                            - George

                                            -----Original Message-----
                                            From: Eric Bennett [mailto:ericb@...]

                                            On Mon, 2 Apr 2001, Dinwiddie, George wrote:

                                            > public class Logger {
                                            > private static Logger singleton = new Logger();
                                            > private Logger() {
                                            > }
                                            > public void log(String message) {
                                            > System.out.println(message);
                                            > }
                                            > public static Logger getInstance() {
                                            > return singleton;
                                            > }
                                            > }

                                            Color me clueless. Why not just add a method

                                            public static void Log(String message) {
                                            getInstance().log( message );
                                            }

                                            and call it with Logger.Log( "lalala" );

                                            The getInstance/log combo doesn't tell you anything more about what state
                                            the logger maintains or what the intent is of keeping an instance of it.

                                            I fail to see how code which does logging via Logger.getInstance().log()
                                            could remain unmodified if you added prefixes or other semantics to the
                                            logger. Since you will have to refactor client code anyway might as well
                                            choose the simplest, prettiest option - which to me is Logger.Log().

                                            - Eric B.
                                          • azami@speakeasy.net
                                            ... blame ... Better, but still not very good. In my opinion. Maybe I d like it better if some of the names were changed - getInstance() by convention
                                            Message 21 of 27 , Apr 2, 2001
                                            • 0 Attachment
                                              --- In extremeprogramming@y..., "Dinwiddie, George"
                                              <George.Dinwiddie@a...> wrote:
                                              > > From: Ryan King [mailto:rking@c...]
                                              > > I would at least think of it, because I the following is
                                              redundant:
                                              > >
                                              > > > String logPrefix = "foo: ";
                                              > > > log(logPrefix, [...]
                                              > > > log(logPrefix, [...]
                                              > > > log(logPrefix, [...]
                                              >
                                              > OK, putting the log prefix each time isn't a great solution. (I'll
                                              blame
                                              > it on my invisible pair.)
                                              >
                                              > How about this. Let's say I start with a singleton class like this:
                                              > ...
                                              > Now, we want to add prefixes:
                                              >
                                              > public class Logger {
                                              > private static final String emptyString = "";
                                              > private String prefix;
                                              > private static Map loggers = new HashMap();
                                              > private Logger(String prefix) {
                                              > loggers.put(prefix, this);
                                              > }
                                              > public void log(String message) {
                                              > System.out.println(prefix+message);
                                              > }
                                              > public static Logger getInstance() {
                                              > return getInstance(emptyString);
                                              > }
                                              > public static Logger getInstance(String prefix) {
                                              > Logger instance;
                                              > if (loggers.containsKey(prefix)) {
                                              > instance = (Logger)loggers.get(prefix);
                                              > } else {
                                              > instance = new Logger(prefix);
                                              > }
                                              > return instance;
                                              > }
                                              > }
                                              >
                                              > Does this smell better?

                                              Better, but still not very good. In my opinion. Maybe I'd like it
                                              better if some of the names were changed - getInstance() by convention
                                              implies singleton. This is only by convention, it doesn't enforce it
                                              in code or anything, and I'd always write code not to care whether the
                                              result of getInstance() is a singleton or not. Also, you'll end up
                                              with (potentially) different log object instances all trying to
                                              operate on the same resource, which could get tricky in a
                                              multi-threaded application. Not unsolvable, just unnecessary. :-)

                                              My idea: Write the logger as a singleton. Write an access class for
                                              the logger (could use the same interface) that is not a singleton and
                                              has state (the prefix).

                                              class PrefixedLogger {
                                              private String prefix;
                                              public String getPrefix() { return prefix; }
                                              public setPrefix(String prefix) { this.prefix = prefix; }

                                              public log(String message) {
                                              Logger.Log(prefix + ": " + message); //See NOTE below
                                              }
                                              }

                                              NOTE: I prefer in some cases to avoid the indirection of
                                              getInstance(), and use static methods instead. It's more work if/when
                                              you need more than one instance, but in the meantime the syntax is
                                              simple and intuitive - just like System.out. If you want proof that
                                              this is simpler, just watch how typical beginning Java programmers
                                              react to all the getInstance() and toolbox stuff!

                                              Reactions?

                                              -Matthew
                                              azami@...
                                            • Eric Hodges
                                              ... PrefixedLogger is fundamentally different from Logger, though. Logger is a Singleton. PrefixedLogger isn t. (I suggested this solution a week or 2 ago,
                                              Message 22 of 27 , Apr 2, 2001
                                              • 0 Attachment
                                                > -----Original Message-----
                                                > From: Dinwiddie, George [mailto:George.Dinwiddie@...]
                                                > Sent: Monday, April 02, 2001 2:40 PM
                                                > To: 'extremeprogramming@yahoogroups.com'
                                                > Subject: RE: Monostates vs. Singletons (Was: Re: [XP] Singletons ==
                                                > Global s?)
                                                >
                                                >
                                                > Good point. I thought of that possibility, but then thought that
                                                > I'd be more likely to collapse them into a single class, as shown,
                                                > at least until I needed to differentiate them. To me, it was an
                                                > easier refactoring.
                                                >
                                                > I notice that your PrefixedLogger is quite different from your
                                                > Logger.
                                                > - It doesn't use a factory to create it.
                                                > - It's not a derived class, so there's more work to convert
                                                > calling code from Logger to PrefixedLogger.

                                                PrefixedLogger is fundamentally different from Logger, though. Logger is a
                                                Singleton. PrefixedLogger isn't.

                                                (I suggested this solution a week or 2 ago, btw.)
                                              • Eric Bennett
                                                ... Oh, agreed. I would start with this about 10 seconds before I made System.out a variable so a new stream could be swapped in for testing. ... Less in my
                                                Message 23 of 27 , Apr 2, 2001
                                                • 0 Attachment
                                                  On Mon, 2 Apr 2001, Dinwiddie, George wrote:

                                                  > As for your suggestion, if you're going to go that
                                                  > route, why not just condense it to
                                                  >
                                                  > public class Logger {
                                                  > public static void Log(String message) {
                                                  > System.out.println(message);
                                                  > }
                                                  > }
                                                  >
                                                  > In fact, the above is frequently my starting point in a program.

                                                  Oh, agreed. I would start with this about 10 seconds before I made
                                                  "System.out" a variable so a new stream could be swapped in for testing.


                                                  > Does a static method have more or less smell than a singleton
                                                  > accessed via a static factory method?

                                                  Less in my book unless something non-global characterizes the factory.
                                                  Maybe I just don't get it yet.


                                                  - Eric B.

                                                  --
                                                  "LogFlume.add( new Log().add_rider( (FoolishLogger) this ) )"
                                                • Dinwiddie, George
                                                  From: azami@speakeasy.net [mailto:azami@speakeasy.net] ... Well, my experience with the Java run-time-library doesn t suggest that getInstance() implies
                                                  Message 24 of 27 , Apr 2, 2001
                                                  • 0 Attachment
                                                    From: azami@... [mailto:azami@...]
                                                    > [snip]Maybe I'd like it
                                                    > better if some of the names were changed - getInstance() by convention
                                                    > implies singleton. This is only by convention, it doesn't enforce it
                                                    > in code or anything, and I'd always write code not to care whether the
                                                    > result of getInstance() is a singleton or not.

                                                    Well, my experience with the Java run-time-library doesn't suggest that
                                                    getInstance() implies singleton. Check out the various flavors of
                                                    java.util.Calendar.getInstance, for example. Maybe I'm wrong, but I've
                                                    standardized my code to use getInstance() for almost any factory
                                                    method. When I first coded singletons in Java, I used getSingleton(),
                                                    but quickly decided that my client code didn't care whether or not it
                                                    was a singleton. (I think this was about when I first converted a
                                                    singleton to a non-singleton.)

                                                    > Also, you'll end up
                                                    > with (potentially) different log object instances all trying to
                                                    > operate on the same resource, which could get tricky in a
                                                    > multi-threaded application. Not unsolvable, just unnecessary. :-)

                                                    Not so tricky. It's easy to put synchronization inside the Logger
                                                    class to make it thread safe.

                                                    > My idea: Write the logger as a singleton. Write an access class for
                                                    > the logger (could use the same interface) that is not a singleton and
                                                    > has state (the prefix).
                                                    [code snipped]
                                                    > NOTE: I prefer in some cases to avoid the indirection of
                                                    > getInstance(), and use static methods instead. It's more work if/when
                                                    > you need more than one instance, but in the meantime the syntax is
                                                    > simple and intuitive - just like System.out. If you want proof that
                                                    > this is simpler, just watch how typical beginning Java programmers
                                                    > react to all the getInstance() and toolbox stuff!

                                                    Yes, using a static method works. For some reason I tend not to use
                                                    that much any more. Somehow that seems more like a global, to me.

                                                    In any event, I wouldn't judge which is simpler by the reaction of a
                                                    novice programmer. I've seen too many that think sprinkling magic
                                                    numbers around the program is simpler.

                                                    So, among the options are:
                                                    1. using a static method, which implies a global, singleton service,
                                                    if not object.
                                                    2. using a constructor (which perhaps just initializes a Monostate),
                                                    which implies client control over the creation of objects.
                                                    3. using a factory method, which implies to me that the client has
                                                    no knowledge over whether a new object is being created or one is
                                                    being pulled out of a pool (that may only have one element). To others,
                                                    such as yourself, this seems to imply a singleton.

                                                    Except for the amount of typing, I currently think that #3 is just as
                                                    simple and is more general than #1 or #2. I don't use #3 exclusively,
                                                    however, and I'm willing to consider arguments for the alternatives.

                                                    - George
                                                  • Dinwiddie, George
                                                    From: Eric Hodges [mailto:eric.hodges@mongoosetech.com] ... a ... Does the client care whether it s a singleton, or not? To me, it s not that the client has a
                                                    Message 25 of 27 , Apr 2, 2001
                                                    • 0 Attachment
                                                      From: Eric Hodges [mailto:eric.hodges@...]
                                                      > PrefixedLogger is fundamentally different from Logger, though. Logger is
                                                      a
                                                      > Singleton. PrefixedLogger isn't.

                                                      Does the client care whether it's a singleton, or not? To me, it's not that
                                                      the client has a desire to do particular types of logging; it's that the
                                                      client has a responsibility to the application to log significant
                                                      occurrences.

                                                      In fact, I don't think I'd ever want the clients of an class to know
                                                      whether or not it's a singleton. It's not their business. If they
                                                      start making assumptions about that, you might as well use a global.
                                                      At least, that's my thinking.

                                                      So, I don't think that singleton-or-not makes a fundamental difference. I
                                                      think that's an implementation issue that should live inside the class. In
                                                      fact, if we're going to start having different flavors of Logger, I think
                                                      I'd be tempted to refactor Logger into an interface. I might also remove
                                                      the factory method from any class and create a LoggerFactory, instead.

                                                      In any event, I think I'm going to end up with a singleton root logging
                                                      object, because I want a single point of control for the logging output.
                                                      I'll also generally want to merger multiple log streams into one. Perhaps
                                                      I'll want to have multiple log streams, but I wouldn't want that to be
                                                      under the control of the client code that sends the log messages.

                                                      - George
                                                    • Eric Hodges
                                                      ... PrefixedLogger *should* be quite different from Logger. PrefixedLogger isn t a Singleton, so it shouldn t be a subclass of a Singleton. PrefixedLogger
                                                      Message 26 of 27 , Apr 2, 2001
                                                      • 0 Attachment
                                                        > -----Original Message-----
                                                        > From: Dinwiddie, George [mailto:George.Dinwiddie@...]
                                                        > Sent: Monday, April 02, 2001 3:36 PM
                                                        > To: 'extremeprogramming@yahoogroups.com'
                                                        > Subject: RE: Monostates vs. Singletons (Was: Re: [XP] Singletons ==
                                                        > Global s?)
                                                        >
                                                        >
                                                        > From: Eric Hodges [mailto:eric.hodges@...]
                                                        > > PrefixedLogger is fundamentally different from Logger, though.
                                                        > Logger is
                                                        > a
                                                        > > Singleton. PrefixedLogger isn't.
                                                        >
                                                        > Does the client care whether it's a singleton, or not? To me,
                                                        > it's not that
                                                        > the client has a desire to do particular types of logging; it's that the
                                                        > client has a responsibility to the application to log significant
                                                        > occurrences.

                                                        The client doesn't care. I was responding to this:

                                                        > I notice that your PrefixedLogger is quite different from your
                                                        > Logger.
                                                        > - It doesn't use a factory to create it.
                                                        > - It's not a derived class, so there's more work to convert
                                                        > calling code from Logger to PrefixedLogger.

                                                        PrefixedLogger *should* be quite different from Logger. PrefixedLogger
                                                        isn't a Singleton, so it shouldn't be a subclass of a Singleton.
                                                        PrefixedLogger doesn't need a factory method, it can use "new".

                                                        >
                                                        > In fact, I don't think I'd ever want the clients of an class to know
                                                        > whether or not it's a singleton. It's not their business. If they
                                                        > start making assumptions about that, you might as well use a global.
                                                        > At least, that's my thinking.
                                                        >
                                                        > So, I don't think that singleton-or-not makes a fundamental difference. I
                                                        > think that's an implementation issue that should live inside the
                                                        > class. In
                                                        > fact, if we're going to start having different flavors of Logger, I think
                                                        > I'd be tempted to refactor Logger into an interface. I might also remove
                                                        > the factory method from any class and create a LoggerFactory, instead.

                                                        You shouldn't try to make a non-Singleton subclass of a Singleton. If that
                                                        means the clients treat Logger differently from PrefixedLogger, so be it.
                                                      • azami@speakeasy.net
                                                        ... convention ... it ... the ... that ... I ve ... My brain wasn t fully in gear before I engaged my fingers. You ve expressed my true thoughts far better
                                                        Message 27 of 27 , Apr 2, 2001
                                                        • 0 Attachment
                                                          --- In extremeprogramming@y..., "Dinwiddie, George"
                                                          <George.Dinwiddie@a...> wrote:
                                                          >
                                                          > From: azami@s... [mailto:azami@s...]
                                                          > > [snip]Maybe I'd like it
                                                          > > better if some of the names were changed - getInstance() by
                                                          convention
                                                          > > implies singleton. This is only by convention, it doesn't enforce
                                                          it
                                                          > > in code or anything, and I'd always write code not to care whether
                                                          the
                                                          > > result of getInstance() is a singleton or not.
                                                          >
                                                          > Well, my experience with the Java run-time-library doesn't suggest
                                                          that
                                                          > getInstance() implies singleton. Check out the various flavors of
                                                          > java.util.Calendar.getInstance, for example. Maybe I'm wrong, but
                                                          I've
                                                          > standardized my code to use getInstance() for almost any factory

                                                          My brain wasn't fully in gear before I engaged my fingers. You've
                                                          expressed my true thoughts far better than I did. In fact,
                                                          getInstance() implies factory to me, and factory implies more than one
                                                          instance. After all, if there's only one of a thing what the heck do
                                                          you need a factory for? Just use the thing.

                                                          > method. When I first coded singletons in Java, I used
                                                          getSingleton(),
                                                          > but quickly decided that my client code didn't care whether or not
                                                          it
                                                          > was a singleton. (I think this was about when I first converted a
                                                          > singleton to a non-singleton.)

                                                          Ideally, the client code should not know whether the object is a
                                                          singleton. You could argue that Logger.Log() looks more like a
                                                          singleton than Logger.getInstance().Log(), but

                                                          1 - you _can_ introduce instances without changing that interface if
                                                          you need to
                                                          2 - I think the result is simpler, and until you need more complexity
                                                          it's worth it.

                                                          > > Also, you'll end up
                                                          > > with (potentially) different log object instances all trying to
                                                          > > operate on the same resource, which could get tricky in a
                                                          > > multi-threaded application. Not unsolvable, just unnecessary. :-)
                                                          >
                                                          > Not so tricky. It's easy to put synchronization inside the Logger
                                                          > class to make it thread safe.

                                                          You need class-level synchronization. The most intuitive ways of
                                                          synchronizing synchronize on instances. So, two instances could try
                                                          to simultaneously access the same resource. You have to remember to
                                                          protect the resource, not the Logger objects. But since the Logger is
                                                          conceptually representative of the resource, this will be easily
                                                          missed...

                                                          > Yes, using a static method works. For some reason I tend not to use
                                                          > that much any more. Somehow that seems more like a global, to me.

                                                          I think the concept of a "global service" is good for services that
                                                          are global. It is vitally important that (from the client's
                                                          perspective) the service is stateless. One object's use of a global
                                                          service must not impact any other object's use of the service.

                                                          For this reason I think it's important to conceptually separate
                                                          methods for using the service from methods for configuring the
                                                          service.

                                                          E.g., it's safe to use System.out wherever you want, but using
                                                          System.SetOut() is rather heinous if not carefully controlled.

                                                          > In any event, I wouldn't judge which is simpler by the reaction of a
                                                          > novice programmer. I've seen too many that think sprinkling magic
                                                          > numbers around the program is simpler.

                                                          A Java beginner isn't necessarily a novice programmer. Anytime a
                                                          programmer says in frustration, "Why won't it just let me X?!" or "I
                                                          can't believe I need to do X, Y, and Z just to accomplish Q!", there's
                                                          a big red flag about complexity. People experienced in a language are
                                                          used to its unnecessary complexities and tend to overlook them easily.

                                                          > So, among the options are:
                                                          > 1. using a static method, which implies a global, singleton
                                                          service,
                                                          > if not object.

                                                          I like this until something more is needed. As I mentioned, a global
                                                          service does not strike me as a bad thing when you're providing a
                                                          service that is global.

                                                          > 2. using a constructor (which perhaps just initializes a
                                                          Monostate),
                                                          > which implies client control over the creation of objects.

                                                          This seems like a clever trick to avoid having to change a lot of
                                                          client code during a refactoring when you actually do need different
                                                          instances all over the place. IMHO, YAGNI.

                                                          > 3. using a factory method, which implies to me that the client has
                                                          > no knowledge over whether a new object is being created or one is
                                                          > being pulled out of a pool (that may only have one element). To
                                                          others,
                                                          > such as yourself, this seems to imply a singleton.

                                                          As I mentioned, kind of a brain fart. Factory implies things are
                                                          being made. What factory really says to me is that I'm giving up
                                                          control of construction so that the factory can create a class I don't
                                                          know about (or shouldn't care about or don't know enough to choose) -
                                                          like a subclass of the class I asked for, or an implementer of the
                                                          interface I asked for. Factories have to do with abstraction, not
                                                          singleton-ness.

                                                          > Except for the amount of typing, I currently think that #3 is just
                                                          as
                                                          > simple and is more general than #1 or #2. I don't use #3
                                                          exclusively,
                                                          > however, and I'm willing to consider arguments for the alternatives.

                                                          I prefer #1 for global services, and #3 for hiding a variety of
                                                          implementations/subclasse so that client code doesn't need to know
                                                          when new implementations/subclasses are added. These are very
                                                          different uses. I would only ever use #2 if the client code
                                                          conceptually wanted control over object creation and instances. I
                                                          can't really think of a case where the client wants to believe it has
                                                          its own instance but there's no actual need for different instances,
                                                          except maybe as a step during a refactoring between a singleton and
                                                          multipletons (in either direction).

                                                          Best,
                                                          Matthew
                                                          azami@...
                                                        Your message has been successfully submitted and would be delivered to recipients shortly.