可选的成员对象

时间:2010-06-12 00:57:42

标签: c++ design-patterns refactoring

好的,所以你的系统主类周围有很多方法。因此,您可以通过创建新类并将移动方法执行到新类来执行正确的操作并重构。新课程只有一个责任,所有人都对世界是正确的:

class Feature
{
public:
    Feature(){};

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

所以现在你的原始类有一个object类型的成员变量:

  Feature _feature;

您将在主课程中调用。现在如果你多次这样做,你的主类中会有很多成员对象。

现在基于配置可能需要或不需要这些功能,因此在某种程度上可能需要或不需要所有这些对象。

有人可以提出一种改进方法吗?


编辑:基于使用Null对象设计模式的建议,我想出了这个:

定义特征界面的抽象类:

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

    virtual ~IFeature(){}
};

然后我定义了两个实现接口的类,一个真实的实现和一个Null对象:

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;};


};

然后我定义了一个Proxy类,它将根据配置委托给真实对象或null对象:

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

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

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

实现:

   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

然后我在我的主类(或任何需要的地方)使用代理类:

Feature _feature;

_feature.doSomething();

4 个答案:

答案 0 :(得分:3)

auto_ptr本身不会给你带来太多帮助。但是有一个指向一个对象的指针,只有当你需要它时才会懒惰地加载它。类似的东西:

class Foo {
private:
    Feature* _feature;
public:
    Foo() : _feature(NULL) {}
    Feature* getFeature() {
        if (! _feature) {
            _feature = new Feature();
        }
        return _feature;
    }
};

现在,如果您需要有关内存管理的帮助,可以将Feature*包装在智能指针中。但关键不在于内存管理,而是懒惰的创造。这样做的好处是,您无需配置 - 您只需按需付费即可选择性地配置您在启动时创建的内容。有时这就是你所需要的一切。

请注意,此特定实现的缺点是,创建现在在客户端第一次调用他们认为只是一个getter的内容时发生。如果创建对象非常耗时,这可能会给您的客户带来一些冲击,甚至是一个问题。它也使getter非const,这也可能是一个问题。最后,它假设您拥有按需创建对象所需的一切,这对于构造起来棘手的对象可能是一个问题。

答案 1 :(得分:3)

如果缺少某个功能并且正确的做法是忽略该事实并且什么也不做,那么您可以使用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 */ }
}

现在,在MainThing中,如果不存在可选功能,则为其提供NullFeature而非实际null引用的引用。这样,MainThing可以安全地假设_feature不是null

答案 2 :(得分:1)

您的问题描述中有一个时刻,实际上会导致失败。 如果您的功能不可用,则不应“只返回”,您应该在调用之前检查功能的可用性!

尝试使用不同的方法设计主类。可以考虑使用一个名为FeatureMap的类的抽象描述符或类似的东西,它实际上存储了当前类的可用特性。

当您实施FeatureMap时,一切都变得简单明了。只需确保(在致电之前),您的班级此功能,然后才能调用它。如果您遇到调用不受支持的功能的情况,请抛出异常。

另外,这个功能查找例程应该快速(我猜是这样)并且不会影响您的性能。


我不确定我是否直接回答您的问题(因为我对您的问题域没有任何想法,而且,更好的解决方案总是针对特定领域的),但希望这会让你以正确的方式思考。

答案 3 :(得分:1)

关于对Null对象模式的编辑:如果你已经有一个功能的公共接口/私有实现,那么创建一个null实现是没有意义的,因为公共接口可以是你的null实现,没有任何问题)。

具体而言,您可以:

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
};

如果这个代码对性能至关重要,那么这个代码只会受益于NULL实现(即便如此,if(_impl)的成本在大多数情况下都可以忽略不计)。