views:

110

answers:

4

Okay, so you have a load of methods sprinkled around your system's main class. So you do the right thing and refactor by creating a new class and perform move method(s) into a new class. The new class has a single responsibility and all is right with the world again:

class Feature
{
public:
    Feature(){};

    void doSomething();
    void doSomething1();
    void doSomething2();   
};

So now your original class has a member variable of type object:

  Feature _feature;

Which you will call in the main class. Now if you do this many times, you will have many member-objects in your main class.

Now these features may or not be required based on configuration so in a way it's costly having all these objects that may or not be needed.

Can anyone suggest a way of improving this?


EDIT: Based on suggestion to use The Null Object Design Pattern I've come up with this:

An Abstract Class Defining the Interface of the Feature:

class IFeature
{
public:
    virtual void doSomething()=0;
    virtual void doSomething1()=0;
    virtual void doSomething2()=0;

    virtual ~IFeature(){}
};

I then define two classes which implement the interface, one real implementation and one Null Object:

class RealFeature:public IFeature
{
public:
    RealFeature(){};

    void doSomething(){std::cout<<"RealFeature doSomething()"<<std::endl;}
    void doSomething1(){std::cout<<"RealFeature doSomething()"<<std::endl;}
    void doSomething2(){std::cout<<"RealFeature doSomething()"<<std::endl;}
}; 

class NullFeature:public IFeature
{
public:
    NullFeature(){};

    void doSomething(){std::cout<<"NULL doSomething()"<<std::endl;};
    void doSomething1(){std::cout<<"NULL doSomething1()"<<std::endl;};
    void doSomething2(){std::cout<<"NULL doSomething2()"<<std::endl;};


};

I then define a Proxy class which will delegate to either the real object or the null object depending on configuration:

class Feature:public IFeature
{
public:
    Feature();
    ~Feature();

    void doSomething();
    void doSomething1();
    void doSomething2();

private:
    std::auto_ptr<IFeature> _feature;
};

Implementation:

   Feature::Feature()
    {
        std::cout<<"Feature() CTOR"<<std::endl;
        if(configuration::isEnabled() )
        {
            _feature = auto_ptr<IFeature>( new RealFeature() );
        }
        else
        {
            _feature = auto_ptr<IFeature>( new NullFeature() );
        }
    }


    void Feature::doSomething()
    {
        _feature->doSomething();
    }

    //And so one for each of the implementation methods

I then use the proxy class in my main class (or wherever it's required):

Feature _feature;

_feature.doSomething();
+1  A: 

There is one moment in your problem description, that actually would lead to failure. You shouldn't "just return" if your feature is unavailable, you should check the availability of your feature before calling it!

Try designing that main class using different approach. Think of having some abstract descriptor of your class called FeatureMap or something like that, which actually stores available features for current class.

When you implement your FeatureMap everything goes plain and simple. Just ensure (before calling), that your class has this feature and only then call it. If you face a situation when an unsupported feature is being called, throw an exception.

Also to mention, this feature-lookup routine should be fast (I guess so) and won't impact your performance.


I'm not sure if I'm answering directly to your question (because I don't have any ideas about your problem domain and, well, better solutions are always domain-specific), but hope this will make you think in the right way.

Kotti
"You shouldn't "just return" if your feature is unavailable, you should check the availability of your feature before calling it" - I don't agree with that. If a method absolutely requires a certain condition to be met before it can perform its function then the test should be within the method. If you test outside of the function, you'll have to test everywhere that function could be called.
David Relihan
+1 I like your fearure look up idea
David Relihan
@David That approach certainly could benefit you in some situations - *if you pair up all your feature calls with appropriate feature map and embed availability checks inside method calling, this would be great.* You could also try implementing some generic `UseFeature(...)` routine, which would perform the availability check and if it's ok, use the feature.
Kotti
@David Also, the main point of my *"you shouldn't..."* phrase was to mention that you shouldn't **just return**. Attempt to call unsupported feature is an exception and should be handled accordingly.
Kotti
+3  A: 
Owen S.
+2  A: 

If a feature is missing and the correct thing to do is ignore that fact and do nothing, you can get rid of your checks by using the Null Object pattern:

class MainThing {
    IFeature _feature;

    void DoStuff() {
        _feature.Method1();
        _feature.Method2();
}

interface IFeature {
    void Method1();
    void Method2();
}

class SomeFeature { /* ... */ }

class NullFeature {
    void Method1() { /* do nothing */ }
    void Method2() { /* do nothing */ }
}

Now, in MainThing, if the optional feature isn't there, you give it a reference to a NullFeature instead of an actual null reference. That way, MainThing can always safely assume that _feature isn't null.

munificent
+1 for deciphering my over long question and providing a very apt suggestion. I am actually familiar with null object from martin fowler but it did not occur to use it here. Would you implement this with a proxy which returns an object or null object based on config?
David Relihan
I'm not sure. Depends on your specific use case, I think. One option would be to have `MainThing` construct the `NullFeature` initially itself, and then rely on outside code to replace it with a more useful feature class if needed. That way it can guarantee for itself that `_feature` will never be null.
munificent
+1  A: 

Regarding your edit on the Null Object Pattern: If you already have a public interface / private implementation for a feature, it makes no sense to also create a null implementation, as the public interface can be your null implementation with no problems whatsoever).

Concretely, you can have:

class FeatureImpl
{
public:
    void doSomething() { /*real work here*/ }
};

class Feature
{
    class FeatureImpl * _impl;
public:
    Feature() : _impl(0) {}
    void doSomething()
    {
        if(_impl)
            _impl->doSomething();
        // else case ... here's your null object implementation :)
    }
    // code to (optionally) initialize the implementation left out due to laziness
};

This code only benefits from a NULL implementation if it is performance-critical (and even then, the cost of an if(_impl) is in most cases negligible).

utnapistim
+1 Agreed - it is essentially the same but I think it is cleaner as there may be multiple implementations in configuration (Option1, Option2, Option3, Disabled). Also, once I put the method in the "interface" (abstract base class), the compiler will let me know if I'm missing a method. But you do have one less file to update with your version - which is a pretty compelling reason too!!!
David Relihan