0

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.

3 Answers 3

2

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.

6
  • 2
    Likewise, were I telling that joke I wouldn't start from the punchline ;-)
    – user4051
    Commented Jun 2, 2013 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? Commented Jun 2, 2013 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
    Commented Jun 2, 2013 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? Commented Jun 3, 2013 at 8:10
  • 1
    @KoreyHinton Check out yUML - a great little tool for this kind of "off the cuff" diagram.
    – Bevan
    Commented Jun 4, 2013 at 22:31
1

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.

1

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.

2
  • What about the edge cases? Commented Jun 2, 2013 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
    Commented Jun 2, 2013 at 4:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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