Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm creating the design for a browser bookmark merging program and I've ran into a design problem that I've seen before yet I've never come up with a good solution for it. So lets say I have a Browser class:

Browser:
  String bookmarkFilePath
  String type
  Bool bookmarkFileExists()

When my program runs I will want to have hard-coded values of common browsers and the locations of their Bookmarks file:

Object with hard-coded values:
  "~/Library/Application Support/Google/Default/Bookmarks", "Chrome"
  "~/Library/Safari/Bookmarks.plist", "Safari"

Is there a design pattern or object type that could effectively take an object with hard-coded values (Browser name / bookmarks file path) and uses it to instantiate (and possibly manage) other (Browser) objects?

Also, flexibility is important since there are edge cases such as Firefox's file path to the bookmarks file is always different and some searching needs to be done.

EDIT: I will be implementing this in Python. Sorry for not mentioning this before.

share|improve this question
add comment

3 Answers

up vote 2 down vote accepted

I'm reminded of the classic joke with the punchline "I wouldn't start from here.".

Since there is different behaviour associated with each specific browser, it seems to me that you actually have a number of different subclasses of the Browser base class:

Class Diagram

The key difference between the subclasses being the differences in behaviour, not the difference in information structure.

Subclassing for differences in operation is less common than subclassing for differences in information, but it's still valid.

Given these classes, you could register each of them with an IoC container:

Bind<Browser>().To<Chrome>().InTransientScope();
Bind<Browser>().To<Safari>().InTransientScope();
Bind<Browser>().To<Firefox>().InTransientScope();
Bind<Browser>().To<Opera>().InTransientScope();
Bind<Browser>().To<InternetExplorer>().InTransientScope();

(Syntax from NInject, but just typed in off the top of my head. Your IoC container of choice will differ.)

Then, you could define your main BookmarkMerger with this constructor:

public BookmarkMerger(IList<Browser> browsers) { ... }

and rely on the IoC container to give you all the defined implementations, as object instances, ready to go.

If you still needed the folders to be soft-coded in a configuration file, instead of hard-coded in your source, each subclass could load it's own configuration when instantiated.

share|improve this answer
1  
Likewise, were I telling that joke I wouldn't start from the punchline ;-) –  user4051 Jun 2 '13 at 10:21
    
@Bevan I forgot to mention that I'm using Python and from what I've read, Why Is IOC Not Common In Python, has IOC ability built-in. I've been trying to find a good way to accomplish the same dynamic behavior in your answer and I came across a Python decorator pattern example: Implementing the decorator pattern in python. Can the decorator pattern give me the same dynamism? –  Korey Hinton Jun 2 '13 at 15:22
1  
From what I know of the Decorator pattern, it's not heading in the direction you want. However, my python is virtually non-existent (my 12 year old son knows more), so I'm not really qualified to judge the code in that post. That said, a Google search led me to this: Dependency Injection the Python Way –  Bevan Jun 2 '13 at 21:14
    
@Bevan thanks for the link to the IOC python example! If you don't me asking, what program did you use to design the Object diagram you used in your post? –  Korey Hinton Jun 3 '13 at 8:10
1  
@KoreyHinton Check out yUML - a great little tool for this kind of "off the cuff" diagram. –  Bevan Jun 4 '13 at 22:31
show 1 more comment

Put the hard-coded strings into a configuration file, fx using the INI format. That way you can exchange them without touching code.

paths.ini

Chrome="~/Library/Application Support/Google/Default/Bookmarks"
Safari="~/Library/Safari/Bookmarks.plist"

or

chrome.ini

path="~/Library/Application Support/Google/Default/Bookmarks"

safari.ini

path="~/Library/Safari/Bookmarks.plist"

The first variant is better, if you use a factory for the browser objects, the second, if the browser object reads the configuration itself.

share|improve this answer
    
What about the edge cases? –  XåpplI'-I0llwlg'I - Jun 2 '13 at 4:11
    
That's what configuration is for. Just add the correct path to the ini file (or create firefox.ini, depending on which way you choose). –  nibra Jun 2 '13 at 4:14
    
+1 for the config file suggestion! –  Korey Hinton Jun 3 '13 at 8:11
add comment

I would start with an enum with values like safari, chrome, opera ... and a constructor that takes a default path and maybe add methods to handle edge cases.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.