Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Facilitating weak coupling using the Factory Method

Status
Not open for further replies.

thepsion5

Programmer
Aug 31, 2006
4
US
Hi guys,
I'm designing several classes that interact with each other, and I'm doing my best to make sure that these classes are weakly couples wherever possible. This has led me to implement the following design:

I'm constructing a web crawler that consists of several main classes/interfaces:
*Crawler
*CrawlerStrategy
*PageSorter

These three classes do the majority of the work. I also have several classes/interfaces designed mostly to carry data:
*CrawlerPage
*CrawlerLink

These data-encapsulating classes will be instantiated primarily by CrawlerStrategy implementations (as it's responsibility is providing an executing a method for crawling the site). To support weak coupling, The CrawlerStrategy class should instantiate instances of CrawlerLink and CrawlerPage through a factory of some kind, correct? But if so, how should I support weak coupling between the CrawlerStrategy class and the Factory class? I've come up with several ideas:
1. Store a reference to the factory internally for every class that requires it's use - this seems like a poor idea, and a lot of useless coding to get and set the factory.
2. Use a singleton manager of some kind to reference the factory object - Better than the first idea, but that still requires strong coupling between the singlton manager and the classes instantiating the objects, which just seems like i'm moving the dependancy elsewhere in the code.

Any ideas? I'd be happy to clarify anything I can if part of this isn't clear. Thanks in advance!
-Sean
 
I guess I'd like to understand better what your motivation is to support weak coupling ("loose" coupling, as I term it). It's not clear to me that we define coupling in quite the same way.

The result of overly tight coupling is too much communication between objects, which of course creates unnecessary overhead. It is not the idea of one object being dependent on another. I get the feeling that this is what you are attempting to avoid, and this isn't to be considered best practice in all cases. In real life, there are entities that ARE in fact dependent on other entities, and it generally makes sense to model them as such.

Your ideas look good to me on first assessment. Number 1 is the standard way of creating an association between two objects. You have to have the reference in order to access the object. Why shouldn't you make the reference part of the object's state? Number 2 is indeed a refinement. I don't agree that it requires strong coupling between the two, though. I think we define coupling a bit differently. Creating a reference to an object, and storing that reference in another object as an attribute, is not coupling per se. Coupling has to do with then using that reference to access the other object's methods and/or attributes. If you do a lot of that, then you have coupling problems.

Coupling as a concern should be considered along with cohesion. Basically, objects that have poor cohesion have excessive decision logic. If you are too rigorous in eliminating decision logic, you will go too far in the direction of overcoupling. In other words, you will create separate objects to avoid having a given object decide what its functionality is in the context of its current instantiation. This can have the result of then having to query another object for that context. In that case, if done too much, you now have overcoupling.

So, the balancing of cohesion and coupling is basically an art. Considering both at the same time is the path to optimal assignment of functionality to classes.

HTH

Bob
 
Thanks Bob, your response was actually very helpful.
Ok, I think I have a better understanding of what I'm actually trying to do now. I believe that I mislabeled my interesting using the Builder pattern as the Factory pattern, so now I have a firmer grip on what I should be done, I still have a significant question, however:

I would still like to use the factory method to instantiate several classes designed primarily to provide transparant communication between several objects, and I would like to avoid extending classes and rewriting code to change these data-carrying objects' class, so using a factory pattern would make more sense here. For example:

A CrawlerStrategy object passes a representation of a webpage (including but not limited to information about size, links, ext) to CrawlerPageSorter object that stores the page after making sure it doesn't already exist. Currently, I use a class called CrawlerPage (which implements the interface ICrawlerPage) to pass the data from the CrawlerStrategy object to the CrawlerPageSorter object. However, in the future I would like to implement different classes from the ICrawlerPage interface without having to rewrite code in either CrawlerStrategy of CrawlerPageSorter classes; a factory method would make sense here, correct? So instead of a line of code such as "($NewPage = new CrawlerPage(...)" I can use code like this: "$NewPage = CrawlerFactory::makePage(...);"

I also have several classes that provide some generally useful functions, a HTMLParser and URLFormatter; these need to be globally accessable but extensible without replacing code. This idea has led me to create an instance of the Facade pattern called CrawlerManager to store internal references to the two previous classes and an internal reference to a CrawlerFactory object so I can swap out the factory or either of the aforementioned classes without changing any code. So, to sum up this giant, meandering post, I have come up with the following design:

CrawlerFactory
-Creates instances of data-carrying classes

HTMLParser/URLFormatter
-Provides general functionality to any/all classes

CrawlerManager
-Stores internal references to HTMLParser and URLFormatter classes, implements their interfaces and forwards all appropriate function calls to them
-Stores internal reference to CrawlerFactory class and also forwards all appropriate functions to them


Does this make any sense (as a post or a sound design method)? Thanks in advance. :)
 
Yes, it looks like you're very much running on the track I would run on.

Your CrawlerPage does indeed look like a factory pattern product. The factory pattern has an abstract Creator class with a FactoryMethod method. This class is implemented by a ConcreteCreator class, whose FactoryMethod produces a Product class. In your application, CrawlerFactory represents the ConcreteCreator class, makePage represents the FactoryMethod method, and CrawlerPage represents the Product. (The fact that CrawlerPage implements iCrawlerPage is nice, but not required by the Factory pattern.)

<So instead of a line of code such as "($NewPage = new CrawlerPage(...)" I can use code like this: "$NewPage = CrawlerFactory::makePage(...);"

This is precisely the benefit of the Factory pattern. Making it a dependent object allows you to constrain and therefore direct aspects of its instantiation.

Now, one thing I'm missing here is how you manage your CrawlerPage objects. Will you have CrawlerManager keep track of an array of them? That would be my first thought.

Furthermore, I would define more rigorously the nature of the association between CrawlerManager and the other classes. It looks to me for the most part like the CrawlerManager constructor would instantiate the HTMOParser, UMLFormatter, and CrawlerFactory classes. If so, you have a Composition type association. It also looks like the CrawlerFactory would store references to existing pages in some CrawlerPageCollection class or some such.

So, how are you managing the CrawlerPage objects once you create them?

Bob
 
The CrawlerPage objects are primarily instantiated using the CrawlerStrategy since it's purpose is to facilitate the actual crawling of the website. The CrawlerStrategy crawls a page and "deposits" it in the form of a CrawlerPage into an instance of the CrawlerPagesSorter class, which maintains a list of crawled pages through an associative array. The CrawlerStrategy object refers to this class when verifying that a page it is about to crawl has not been previously crawled.
The precise purpose of the CrawlerManager class is to provide a central point of access to the HTMLParser, URLFormatter, and CrawlerFactory classes; it stores an internal reference to each and forwards function calls to them by implementing the interfaces fore each of the three classes. This way I can replace any of the three internal references when I want to switch out its class for another. Having the CrawlerManager implement all three interfaces seemed like a clumsy solution at first, but I found that it was the best way to make sure the classes doing all the work (CrawlerStrategy and CrawlerPageSorter) from directly referencing the classes so to sum it up:

CrawlerPageSorter (Implements ICrawlerPageSorter)
-Maintains a list of crawled pages and information about them as an array of CrawlerPage objects
-Determined whether a specified URL has already been crawled

CrawlerStrategy (Implements ICrawlerStrategy)
-Implements a method used to crawl a website
-Sends crawled pages to the CrawlerPageSorter as CrawlerPage objects
-Creates CrawlerPage objects through the factory methods of CrawlerManager

CrawlerManager (Implements IHTMLParser, IURLFormatter, ICrawlerFactory)
-Provides a single point of access to HTMLParser and URLFormatter classes by delegating operations so the actual HTMLParser and URLFormatter classes can vary
-Provides a single point of access to the CrawlerFactory class so the class can vary, also delegates factory operations to it by implementing the interface

Does this sound like a smart idea? Feel free to let me know if i'm insane ;)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top