Yes, if you provide public methods in Browser for every method in BookmarkManager, that is most likely going to be a bad design.
First, if the client code needs to do all these things to bookmarks, why can't it just interact with BookmarkManager directoy? Why does it have to go through the Browser object? Another option is to create a BookmarkCommand object that you can configure and pass into the Browser. On Tue, Feb 17, 2009 at 5:13 PM, Henry <[email protected]> wrote: > > Thank you everyone for your input! > > Let say I have a Browser, and it has a bookmark sub-system that manage > a collection of bookmarks. > > Browser.gotoURL(url) > Browser.openPage(filePath) > Browser.addBookmark(name, url) > > So far so good, but shouldn't another object manages bookmarks? So I > created BookmarkManager, and Browser has-a BookmarkManager > > BookmarkManager.add(name,url) > BookmarkManager.remove(bookmarkId) > BookmarkManager.sort() > BookmarkManager.getBookmarkIds() // return a list of ids > BookmarkManager.reorder(bookmarkIds) // get a list of ids, and > reorder them base on the other of the ids > > Now Browser has a BookmarManager > > function init() { > variables.bookmarkManager = createObject > ("component","BookmarkManager") > } > > > Things looks good so far? > > The browser has a "Sort Bookmarks" button, what should it calls? > > Solution 1: Browser.getBookmarkManager().sort() > Solution 2: Browser.sortBookmarks() // which calls > variables.bookmarkManager().sort() > > You guys said solution 2 is better, which I agreed. Now as the > Browser has buttons to add, remove, move bookmarks into folders, > etc... > > The Browser object will end up having every public methods of > BookmarkManager... which is the an example of the "Middle Man" anti- > pattern as Mr. Brian Kotek pointed out. > > What should I do to better model this? > > > Regards, > Henry Ho > > > On Feb 17, 1:38 pm, Peter Bell <[email protected]> wrote: > > Yes it would. But then we've got to ask the question, what are all of > > these detailed tasks you need to do with the sub objects and is that > > the only way to solve the problem? Instead of modeling a room and > > futzing with windows, couldn't we just have a temperature object with > > a regulate() method which would take care of details like turning on > > the fan or opening the windows? > > > > As Brian said, generally if you have objects with lots and lots of > > pass through models, it's quite likely that you don't have the most > > elegant abstractions in your model or that you're providing control > > that is too granular. Can't you just trust the room to > > room.lowertemperature() or do something else at a higher level rather > > than giving really granular control over every single object in the > > room? > > > > On Feb 17, 2009, at 4:26 PM, Henry Ho wrote: > > > > > No, I'm sorry this is not a real app. I am building something else, > > > but I don't think it is appropriate for me to post the actual > > > software model we're working on at work. I'm not sure if my client > > > will be okay with me asking on a public mailing list. > > > > > Although the Room / Window example sounds ridiculous on the surface, > > > it is where the methods should be placed that puzzled me. > > > > > To use a super abstract example, it'll be like.. > > > > > 1 ObjectA has an ObjectX, ObjectY, and ObjectZ. > > > > > ObjectX, ObjectY and ObjectZ have n public methods each (where n may > > > be = 10+). > > > > > If I push all behaviors onto ObjectA, then A will have all 30+ > > > public methods (+ its own). Yes, we'll respect the Law of Demeter, > > > and no one will know ObjectA really has ObjectX/Y/Z, but wouldn't > > > ObjectA become super fat? > > > > > Regards, > > > Henry Ho > > > > > On Tue, Feb 17, 2009 at 1:06 PM, Peter Bell <[email protected]> > > > wrote: > > > > > I'm a little confused. Do you actually have a customer paying you to > > > build the application below? If not, and you are building a real OO > > > app I'd suggest using that as the example. There are only rules of > > > thumb in OO design and they are incredibly context specific. Try > > > asking an artist "which color is best" for a painting . . . As such, > > > using some kind of generic example is usually a really bad way to go > > > (which was why I always hated the OO books talking about engines being > > > composed within a car). > > > > > Of course, apologies if this is a real app that you *are* building > > > right now for a client to mock up a room control system or something. > > > It's just not all that often I see such apps in the CF world. > > > > > Best Wishes, > > > Peter > > > > > On Feb 17, 2009, at 3:45 PM, Henry wrote: > > > > > > The Room object is getting bloated, what should I do? > > > > > > Room has Windows, and you guys advised me to use Room.closeWindow(). > > > > That's what I did. However, instead of one getWindow() function in > > > > Room, Room now has 10 methods related to operations for Window. > > > > > > Now Room also has an owner of type User , and owner handles the > > > login > > > > (), changePassword(), etc. > > > > Room has an owner, that makes sense. > > > > Which solution's better now? > > > > > > Solution 1: // 1 getOwer() method in Room > > > > > > Room.getOwner().changePassword(oldPassword, newPassword) > > > > Room.getOwner().validatePassword(password) > > > > Room.getOwner().setName(newName) > > > > > > Solution 2: // 3 methods in Room > > > > > > Room.changeOwnerPassword(oldPassword, newPassword) > > > > Room.validateOwnerPassword(password) > > > > Room.setOwnerName(newName) > > > > > > How about... Plan? Let's say Plan has method isEnable(featureName). > > > > The view layer needs to call this function to determine which Tab to > > > > show. > > > > Room has a plan, that makes sense. (One user can have many Rooms, > > > > each Room has a plan) > > > > > > Solution 1: // 1 getPlan() method > > > > > > Room.getPlan().isEnable("customizeWindow") > > > > Room.getPlan().isEnable("selectStyle") > > > > Room.getPlan().isEnable("ceilingFan") > > > > > > Solutions 2: > > > > Room.canCustomizeWindow() > > > > Room.canSelectStyle() > > > > Room.hasCeilingFan() > > > > > > Now I'm confused. Do you guys still think solution 2 is the > > > preferred > > > > choice? Even thought it can make my Room object bloated with > > > several > > > > times more methods? > > > > > > Thank you! > > > > Henry Ho > > > > > > On Feb 12, 12:53 pm, Henry <[email protected]> wrote: > > > >> Thanks a lot. > > > > > >> I liked Solution 2 too, but found the method Room.closeWindow() a > > > >> little awkward. I guess it is actually fine, after hearing the > > > >> reasons from you guys. > > > > > >> Yes, this is a high tech room that closes its own Window. :) > > > > > >> Henry Ho > > > > > >> On Feb 12, 11:20 am, Jared Rypka-Hauer <[email protected]> > > > >> wrote: > > > > > >>> Principles: Tell don't ask, encapsulation, domain object modeling > > > > > >>> Unequivocally option 2. Option 1 doesn't actually model anything > > > >>> other > > > >>> than relationships. A real domain model reflects relationships > > > thru > > > >>> composition but uses behavior to shield peer objects from their > > > API. > > > >>> This allows them to act only upon those relationships where the > > > are, > > > >>> in the eyes of the domain, subject matter experts. Domain objects > > > >>> like > > > >>> Room, Window and Door should all have behaviors. Given the > > > >>> confines of > > > >>> the example (which is kind of a bad one, really), > > > Room.closeWindow() > > > >>> is perfectly appropriate even though in real life you would > > > probably > > > >>> say Person.closeWindow(Room,Window); since Rooms don't actually > > > >>> close > > > >>> their own windows... ;) > > > > > >>> Hey, it could even be that Person.closeWindow() has private > > > >>> functions > > > >>> and state like variables.currentRoom and findClosestWindow(), so > > > >>> Person.closeWindow() would (in my model anyway) use Person's state > > > >>> to > > > >>> find the closest window in a room. > > > > > >>> OTOH, internally, Room's protected scopes could do the same thing > > > >>> thru > > > >>> findPesonClosestToWindow().closeWindow(variables.myWindow), or any > > > >>> combination of the above. In any and/or all cases though, they all > > > >>> focus on encapsulation by implementing the behaviors in the > > > >>> appropriate domain object allowing everyone to interact without > > > >>> worrying about objects they need't worry about. In providing > > > >>> closeWindow(), Room is actually encapsulating the operations > > > >>> required > > > >>> to close or open the window and as a result is actually OO. > > > > > >>> Along those same lines, option 2 abides by the principle of "Tell, > > > >>> don't ask" which is a key OO concept in helping the developer to > > > >>> establish behaviors on domain objects. If you're telling a domain > > > >>> object to take action in its domain space, you're unconcerned with > > > >>> the > > > >>> implementations of it's composites (so you're only working with > > > the > > > >>> API of the adjacent object... in this case, the Room) and letting > > > >>> the > > > >>> object itself worry about the internal details of actually closing > > > >>> the > > > >>> window. > > > > > >>> Option one is technically procedural, queueing up operations to be > > > >>> executed in sequence by some object that knows far too much about > > > >>> its > > > >>> environment. Room.getWindow().close()... asking an object for > > > >>> another > > > >>> object, then taking direct action on that object yourself is a > > > very > > > >>> procedural approach. It works just fine, but it's not OO... no, > > > >>> really, it's not. I promise. "get" is not a behavior! ;) > > > > > >>> I'm not saying I like one better than the other, because the "It > > > >>> Depends Principle" says that either could be more valid than the > > > >>> other > > > >>> depending on context. hehehehe > > > > > >>> J > > > > > >>> On Feb 12, 2009, at 12:49 PM, Henry wrote: > > > > > >>>> Let's say.. there's a Room. Room has Window, and Door. Room > > > has a > > > >>>> state (empty, not empty). And this Room is smart that it only > > > lets > > > >>>> you close the Window when it is not empty. > > > > > >>>> So.. we have: > > > > > >>>> Room.isEmpty() > > > >>>> Window.open() > > > >>>> Window.close() > > > > > >>>> Now... since Window.close() needs to check if room is empty > > > first, > > > >>>> what should be a better solution? > > > > > >>>> // Solution1: > > > >>>> Room.init() > > > >>>> Window.init(room) // window has reference to Room > > > >>>> Window.close() // checks if Room is empty first by > > > >>>> calling > > > >>>> room.isEmpty() > > > > > >>>>> Room.getWindow().close() > > > > > >>>> // Solution2: > > > >>>> Room.init(Window window) > > > >>>> Window.init() // window has no reference to Room > > > >>>> Window.close() // will close itself w/o checking > > > > > >>>>> Room.closeWindow() // Room object checks if it isEmpty(), if > > > >>>>> yes, > > > >>>>> then it calls window.close() > > > > > >>>> What do you guys think? Which one is the better solution? Why? > > > >>>> base > > > >>>> on which OO principle? > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "CFCDev" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/cfcdev?hl=en -~----------~----~----~----~------~----~------~--~---
