Registry Design Pattern...Good or Bad

Registry design pattern...good or bad?

The article claims it is using the "registry design pattern"; is that the universal name for this design in the industry?

Yes, but the implementation could obviously differ. Basically, a registry is a container for shared objects. In the really basic version, you could use an array. As such, the variable $GLOBALS could be called a registry.

Is there another similar patter out there that would be a better option?

There are two variations of a registry. There is the global registry (Which is far the most common, and which this is an example of). And there is a local registry. A local registry is passed to objects that need it, rather than obtained through a global symbol (static class, singleton etc.). A local registry has a lower degree of coupling, but is also slightly more abstract, so there is a tradeoff there.

You can also go even further and use full dependency injection, where you explicitly pass all the dependencies to the objects that need them. This can be a bit tedious in larger applications. You can couple this with a dependency injection container, which is a piece of code that "knows" which dependencies which classes have. This is even more complex than a local registry, but has a very low degree of coupling.

Is this pattern considered to be good practice to implement in the context of an MVC framework?

It's common practise. If it's good or bad is a judgement call. Personally I'm willing to accept some complexity in return of decoupling, but ymmv.

Is there ANYTHING bad about the Registry design pattern?

You mean a registry of Singletons, right? If so, it sounds like all you really want is access to three global objects everywhere, but contained inside another object.

So if you wrote cache.php, sessions.php, and database.php, which define the classes Cache, Sessions, and Database, you want to contain them all inside a Registry object defined in registry.php.

First of all, it's great to control the ORDER of instantiation this way. It's better than simply doing a require_once of cache.php, sessions.php, and database.php, and inside of them you define not only the class but the single global instance of it. That controls the ORDER of instantiation by how you include/require it. Kind of sleazy. Better to have your Registry object, that when it gets created and becomes a $registry global, first thing is does is control the creation of your globals in the order and how you want.

Second of all, it's great to have a single Registry.php that has a single $registry global. Defining globals here and there over various files gets hard to manage.

Now that I've agreed with you, I pose an important question to you. How do you see these being different:

$registry->getObject('session');
$registry->getObject('database');
$registry->getObject('cache');

versus:

$registry->getSession ();
$registry->getDatabase ();
$registry->getCache ();

Personally, I like the latter. You aren't using a string "session" to refer to a Session object, obtained through a super-generic getObject. Instead, you are using getSession() to get a Session. It reads better.

Your registry, after all, knows all about the three globals, it creates them explicitly, so it's already locked into a single purpose. Adding concrete methods also tied to its single purpose isn't "weak" or "bad". Instead, I think it's less code and easier on the eyeballs.

What is the best OO Design Pattern for handling Windows Registry (or filesystem) objects?

Why not loading data "on demand"? Access a list of children nodes or a single node when you need to. Avoiding preloaded data or data loaded too soon will reduce the number of obsolete entries.

Since the obsolete entries may still exist (ie. if you loaded the list of children nodes 1 ms. ago, there is no guarantee that every child is still there), recheck the validity of data at each modification. For example, if you are:

  1. reading the list of children nodes, then
  2. searching through the list for a node, then,
  3. for every matching node, replacing a value,

you may not check for valid data at the second state, but you MUST check if the node exists at the third state, before replacing a value. If the check fails, then throw an exception.

There is no such a thing as transactions for Registry. But you may try to make something similar, much more basic, depending on the context. If you are saving some keys to registry and must be sure that those keys are not modified meanwhile, save the existing values, start saving, and when finished, recheck the values. If they are wrong, revert to previous state (thus keeping the values modified by another program during transaction).

You may also want to search for other strategies, again depending on the context. For example, if you are moving a bunch of registry keys from one place to another and you know that those keys may be modified or deleted meanwhile or new ones may be created, move them, checking one by one, then recheck if there are still keys to move (ie. the new ones), move the new ones, recheck, etc.

Disposable Registry: good pattern?

Ostensibly, this approach makes sense when you cannot make the disposal thread-safe (for example when talking to COM objects, which MUST be released on the same thread). However, in practice, you would find that this approach leads to objects living longer than they should.

I would strive to make the disposal thread safe, that way you can call Dispose from the finalizer and achieve truly automatic lifetime management. You have to be careful as might not be appropriate for some types of resources - like file or network handles, which might need tighter control. Otherwise, this is the best solution to this problem.

If the disposal HAS to be on the same thread then you are in a bit of a pickle. If the object needing disposing is in the model layer (as in business rules object) - it's quite likely it has layers of UI on top of, needing complex logic to dispose it (like events after a window is closed). It's a lose/lose situation and a choice between objects living forever (like your original solution) and complex disposal logic (which turns ugly pretty quickly).

Perhaps something to experiment with. You could separate the disposable resource into its own class and have the factory maintain a strong reference to it. The resource object maintains a weak reference back to business object. When the business object is finalized, WeakReference will return null, thus enabling you to make pass over the disposables and dump the ones that are no longer needed.

public class Global {
private static readonly List<Resource> Disposables = new List<Resource>();

public HeavyLifter GetHeavyLifter()
{
var resource = new HeavyLifterResource();
var heavyLifter = new HeavyLifter(resource);
resource.BusinessObject = heavyLifter;
Disposables.Add(resource);
}

public void DisposeAll()
{
Disposables.ForEach(d => d.CleanUp());
}
}

public abstract class Resource : IDisposable {

WeakReference<object> m_BusinessObject;
public WeakReference<object> BusinessObject {get;set;}

public CleanUp() {
if (!m_BusinessObject.IsAlive)
Dispose();
}
}

public HeavyLifter {
public HeavyLifter (Disposable d) {
m_resourceObj = d;
}

HeavyLifterResource m_resourceObj;
}

public class HeavyLifterResource :Resource {
public void Dispose() {
//disposal
}
}

Let me again reiterate that the above approach is only appropriate for a certain class of objects. You wouldn't want to handle your network connections in such fuzzy way, but you can, for example, do this for business objects that need a network connection to dispose themselves. Even then, this is only appropriate when such connection is persistent through the lifetime of the application.

How to implement Registry pattern in C++, using single registry for many interface implementation

  /*!
*
* \brief Allow to implement the Registry pattern applied to interface implementation
*
* A registry is needed for each implemented interface. Then, implementation are
* registered into it, using arbitrary string as identifier. Once registered, the
* registry is able to provide a concrete instance of a type, given is string identifier.
*
*/
template <class InterfaceType, class IdType = std::string>
class ImplementationRegistry
{
typedef boost::function0<InterfaceType *> Creator;
typedef std::map<IdType, Creator> Creators;
Creators m_Creators;

public:
/*!
*
* \brief Register a new concrete type, indexed with given identifier
*
* \note the concrete type must be a specialized type of the interface
* managed by the registry.
*/
template <class ConcreteType>
void Register(const IdType &identifier)
{
ConstructorWrapper<ConcreteType> wrapper;
Creator creator = wrapper;
m_Creators[identifier] = creator;
}

/*!
*
* \brief return a concrete implementation og the managed interface according to an identifier
*
* \return an implementation or null in the identifier is unknown
*/
InterfaceType *Create(const IdType &identifier)
{
InterfaceType *result = nullptr;
auto it = m_Creators.find(identifier);
if (it != m_Creators.end())
{
result = it->second();
}
return result;
}

protected:

template<class ConcreteType>
struct ConstructorWrapper
{
InterfaceType *operator()() const { return new ConcreteType(); }
};
};
}

Registry or Singleton pattern in PHP?

That depends on your application. If you still need 3 out of the 4 classes, then it'd be more ideal to use the Registry than to handle the 3 independently only because you don't need the fourth. Loading the classes lazily would be one approach to reduce memory footprint, but then you need to instruct the registry when to create the objects and that's not much different than handling singletons. Alternatively, you could create an n-parameter constructor or use an array to instruct your Registry which classes to instantiate during construction.

class Registry {
public $class1;
public $class2;

function __construct($uses) {
foreach($uses as $class) {
$this->{$class} = new {$class}();
}
}

}

Then instantiate your Registry by specifying which classes to instantiate.

$reg = new Registry(array('class1'));

You would obviously want your constructor to handle zero parameters to account for instantiating all classes by default.

How to apply registry pattern to make select class depend on input obey open closed principle?

This can become quite verbose codewise so I use words instead.
A definition of the registry pattern :

A registry is a global association from keys to objects, allowing the
objects to be reached from anywhere. It involves two methods: one that
takes a key and an object and add objects to the registry and one that
takes a key and returns the object for the key

The thing here is that the registry doesn't know how to build the object, just how to retrieve it. This is a significant difference to the creational patterns.

Basically your fruit should can change to

#include <string>
class Fruit{
public:
virtual std::string key() const = 0;
virtual void hi(std::string username) = 0;
};

And now you introduce a registry

class FruitRegistry final {
public:
bool register(Fruit* fruit);
Fruit* locate(std::string key);

private:
std::map<string, Fruit*> registry;
};

The means of registering/retrieving fruits should be the same whatever the fruit. Here it can be done using a map string to fruit. You can also design the class fruit so it uses an accept method, which is quite useful when the input is complex (think initializing a fruit depending on its description).

When it is useful ? When it is used behind an interface to access a type of resources, like img.load("cats.jpg"). The format jpg, bmp, png are quite different and might need a separate engine for each, or one for jpg, the other for both bmp and png. But the user doesn't care about those details. Note that more and more images type can be added in the future without touching the image loading.

The issue is that to provide the nice img.load("cats.jpg") the registry mechanism underneath can be complex to design. You need to ask yourself :

  • Do the user care about apple and oranges (if no stop here, you don't need a registry)? Or does he just want to eat a fruit ?
  • How easy will it be to eat fruits the registry is implemented? (should be a single line)
  • How often or how long new types of fruits can be added? (should be forever)
  • How different are the fruits ? (should be completely, just that they can be eaten)

What are drawbacks or disadvantages of singleton pattern?

Paraphrased from Brian Button:

  1. They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell.

  2. They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle.

  3. They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases.

  4. They carry state around for the lifetime of the application. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other.



Related Topics



Leave a reply



Submit