如何在工厂模式中正确实现具有自己函数的派生类?

huangapple go评论72阅读模式
英文:

How to properly implement derived classes with their own functions in a Factory Pattern?

问题

我遇到了使用工厂模式时派生类具有自己函数的问题。请分享一下您在这种情况下如何设计面向对象编程。

假设我有一个通用类 B,以及许多派生类,命名为 D1、D2、D3 等。每个这些类都有自己的函数,分别命名为 F1、F2、F3 等。使用工厂模式,我们将会有如下程序:

class FactoryPattern {
    static B* create(string type) {
        if (type == "D1")
            return new D1();
        if (type == "D2")
            return new D2();
        ...
    }
};

然而,B 必须具有所有 F 的虚拟函数,并且对于每个派生类,我将打印(或引发错误或其他操作)以防止用户使用这些函数。

使用下面的实现,程序会呈现极大的扩展性问题,因为当我们需要为例如类 D3 的函数 F3 进行实现时,我们需要同时更新 D1D2 的程序。

class B {
protected:
    virtual void F1() = 0;
    virtual void F2() = 0;
};

class D1: public B {
public:
    void F1() {
        cout << "F1 from D1\n";
    }

    void F2() {
        cout << "This function is not implemented\n";
    }
};

class D2: public B {
public:
    void F1() {
        cout << "This function is not implemented\n";
    }

    void F2() {
        cout << "F2 from D2\n";
    }
};

我考虑过为类 B 使用通用函数,只在需要时进行覆盖,然而,与工厂模式结合使用时,返回的指针会直接调用 B::F1B::F2,而这两者都没有实现。

class B {
protected:
    void F1() {
        cout << "This function is not implemented\n";
    }
    void F2() {
        cout << "This function is not implemented\n";
    }
};

class D1: public B {
public:
    void F1() {
        cout << "F1 from D1\n";
    }
};

class D2: public B {
public:
    void F2() {
        cout << "F2 from D2\n";
    }
};

编辑: 函数 F 可以接受不同类型的参数,并且命名也是特定的,所以我不能使用通用函数像 foo

编辑2: 为了更详细的问题,让 Inference 作为通用类(B),我有两个派生类,分别命名为 ClassifierDetector。对于初始化,它们都需要 model_path,然而,Detector 还可以接受输出信息列表(bounding_boxlabel 等),然后它们的初始化将需要不同类型的参数。还有许多其他特殊函数,这只是一个示例。

class Inference {
public:
    virtual void Initilisation(string model_path) = 0;
    virtual void Initilisation(string model_path, vector<string> output_information) = 0;
};

class Detector: public Inference {
public:
    void Initilisation(string model_path) {
        cout << "Not implemented\n";
    }

    void Initilisation(string model_path, vector<string> output_information) {
        // 进行一些初始化
        // 例如,output_information 可以是 {"label", "conf", ...}
    }
};

class Classifier: public Inference {
public:
    void Initilisation(string model_path) {
        // 进行一些初始化
    }

    void Initilisation(string model_path, vector<string> output_information) {
        cout << "Not implemented\n";
    }
};
英文:

I face a problem with derived classes having their own functions when using Factory Pattern. Please share how you design OOP in this case.

Assume I have a general class B, and many derived classes, named D1, D2, D3, etc. Each of these classes has its own function, named F1, F2, F3, etc. respectively. Using Factory Pattern, we will have a program like this:

class FactoryPattern {
    static B* create(string type) {
        if (type == &quot;D1&quot;)
            return new D1();
        if (type == &quot;D2&quot;)
            return new D2();
        ...
    }
};

However, B must have its virtual functions for all of the F, and for each of the derived classes, I will print (or throw an error or anything else) to prevent the user from using the functions.

With the below implementation, the program will scale tremendously, as when we need to implement a new function, for example, function F3 for class D3, we need to update the program for both D1 and D2.

class B {
protected:
    virtual void F1() = 0;
    virtual void F2() = 0;
};

class D1: public B {
public:
    void F1() {
        cout &lt;&lt; &quot;F1 from D1\n&quot;;
    }

    void F2() {
        cout &lt;&lt; &quot;This function is not implemented\n&quot;;
    }
};

class D2: public B {
public:
    void F1() {
        cout &lt;&lt; &quot;This function is not implemented\n&quot;;
    }

    void F2() {
        cout &lt;&lt; &quot;F2 from D2\n&quot;;
    }
};

I thought about using a general function for class B, and just overriding if needed in the derived class, however, when combining with Factory Pattern, the returned pointer calls directly to B::F1 and B::F2, which are not implemented.

class B {
protected:
    void F1() {
        cout &lt;&lt; &quot;This function is not implemented\n&quot;;
    }
    void F2() {
        cout &lt;&lt; &quot;This function is not implemented\n&quot;;
    }
};

class D1: public B {
public:
    void F1() {
        cout &lt;&lt; &quot;F1 from D1\n&quot;;
    }
};

class D2: public B {
public:
    void F2() {
        cout &lt;&lt; &quot;F2 from D2\n&quot;;
    }
};

Edit: The function F can take different types of parameters, and the naming is also specific, so I can not use a general function like foo.

Edit2: For a more detailed problem, let Inference be the general class (B), and I have 2 derived classes, named Classifier, and Detector. For initialisation, all of them take model_path, however, Detector can take the list of output information (bounding_box, label, etc.) in addition, then the initialisation of them will take different types of parameters. There are many other special functions, this is just an example.

class Inference {
public:
    virtual void Initilisation(string model_path) = 0;
    virtual void Initilisation(string model_path, vector&lt;string&gt; output_information) = 0;

};

class Detector: public Inference {
public:
    void Initilisation(string model_path) {
        cout &lt;&lt; &quot;Not implemented\n&quot;;
    }

    void Initilisation(string model_path, vector&lt;string&gt; output_information) {
        // do some initialisation
        // for example, output_information can be {&quot;label&quot;, &quot;conf&quot;, ...}
    }
};

class Classifier: public Inference {
public:
    void Initilisation(string model_path) {
        // do some initialisation
    }

    void Initilisation(string model_path, vector&lt;string&gt; output_information) {
        cout &lt;&lt; &quot;Not implemented\n&quot;;
    }
};

答案1

得分: 1

声明每个派生类的新函数有点违背多态性的初衷。通常的做法是在基类中声明一个virtual函数,然后在派生类中覆盖它以实现各自的功能。

示例:

#include <iostream>
#include <memory>

class B
{
public:
    virtual void foo() = 0;
};

class D1: public B
{
public:
    void foo() override
    {
        std::cout << "I'm a D1\n";
    }
};

class D2: public B
{
public:
    void foo() override
    {
        std::cout << "I'm a D2\n";
    }
};

int main()
{
  std::unique_ptr<B> pD1 = std::make_unique<D1>(D1());
  pD1->foo();

  std::unique_ptr<B> pD2 = std::make_unique<D2>(D2());
  pD2->foo();

  // pD1 and pD2 are of the same type, could be stored in the same vector etc.
}
英文:

Declaring a new function for each derived class kind of defeats to point of polymorphism. The usual way to go is to declare one virtual function in the base class, then to override it in the derivatives with their own functionality.

Example:

#include &lt;iostream&gt;
#include &lt;memory&gt;

class B
{
public:
    virtual void foo() = 0;
};

class D1: public B
{
public:
    void foo() override
    {
        std::cout &lt;&lt; &quot;I&#39;m a D1\n&quot;;
    }
};

class D2: public B
{
public:
    void foo() override
    {
        std::cout &lt;&lt; &quot;I&#39;m a D2\n&quot;;
    }
};


int main()
{
  std::unique_ptr&lt;B&gt; pD1 = std::make_unique&lt;D1&gt;(D1());
  pD1-&gt;foo();

  std::unique_ptr&lt;B&gt; pD2 = std::make_unique&lt;D2&gt;(D2());
  pD2-&gt;foo();

  // pD1 and pD2 are of the same type, could be stored in the same vector etc.
}

答案2

得分: 1

以下是要翻译的内容:

至于我所学的工厂设计模式及其用途。我在这篇文章中提到了。请仔细阅读。我希望它能解决你的疑问。

查看链接:https://deepakatariya.com/factory-design-pattern-can-help/

英文:

As far as I studied about factory design pattern and it's uses. I have mentioned in this article. Please go through it. I hope it solves your doubt.

Check it out : https://deepakatariya.com/factory-design-pattern-can-help/

答案3

得分: 0

以下是您要翻译的内容:

You would need to make an abstract baseclass first and make sure the factory returns unique pointers to that. unique_ptr because naked new/delete is not recommended in current C++. SO you will transfer ownership of the pointer to the caller of the factory.

// 首先,您需要创建一个抽象基类,并确保工厂函数返回指向该基类的唯一指针。使用 unique_ptr,因为在当前的 C++ 中不推荐使用裸指针的 new/delete。因此,您将指针的所有权传递给工厂函数的调用者。

#include <iostream>
#include <memory>
#include <string>
#include <string_view>

// When using a factor always start with an
// abstract baseclass (interface)

// 在使用工厂模式时,始终从创建抽象基类(接口)开始。

class my_interface_t
{
public:
virtual void do_something() = 0;
};

// then concrete classes, note the override keyword

// 然后创建具体的类,注意使用 override 关键字。

class class_a_t :
public my_interface_t
{
public:
void do_something() override
{
std::cout << "class_a_t::do_something()\n";
}
};

class class_b_t :
public my_interface_t
{
public:
void do_something() override
{
std::cout << "class_b_t::do_something()\n";
}
};

class factory_t
{
public:
std::unique_ptr<my_interface_t> create(std::string_view name)
{
// do NOT use new/delete in current C++

    if (name == "A") return std::make_unique&lt;class_a_t&gt;();
    if (name == "B") return std::make_unique&lt;class_b_t&gt;();

    throw std::invalid_argument("invalid class name");
}

};

int main()
{
factory_t factory;
auto a = factory.create("A");
auto b = factory.create("B");

a-&gt;do_something();
b-&gt;do_something();

return 0;

}

// 主函数以及其他代码部分没有需要翻译的内容。
英文:

You would need to make an abstract baseclass first and make sure the factory returns unique pointers to that. unique_ptr because naked new/delete is not recommended in current C++. SO you will transfer ownership of the pointer to the caller of the factory.

#include &lt;iostream&gt;
#include &lt;memory&gt;
#include &lt;string&gt;
#include &lt;string_view&gt;

// When using a factor always start with an
// abstract baseclass (interface)

class my_interface_t
{
public:
    virtual void do_something() = 0;
};

// then concrete classes, note the override keyword

class class_a_t :
    public my_interface_t
{
public:
    void do_something() override
    {
        std::cout &lt;&lt; &quot;class_a_t::do_something()\n&quot;;
    }
};

class class_b_t :
    public my_interface_t
{
public:
    void do_something() override
    {
        std::cout &lt;&lt; &quot;class_b_t::do_something()\n&quot;;
    }
};


class factory_t
{
public:
    std::unique_ptr&lt;my_interface_t&gt; create(std::string_view name)
    {
        // do NOT use new/delete in current C++

        if (name == &quot;A&quot;) return std::make_unique&lt;class_a_t&gt;();
        if (name == &quot;B&quot;) return std::make_unique&lt;class_b_t&gt;();

        throw std::invalid_argument(&quot;invalid class name&quot;);
    }
};


int main()
{
    factory_t factory;
    auto a = factory.create(&quot;A&quot;);
    auto b = factory.create(&quot;B&quot;);

    a-&gt;do_something();
    b-&gt;do_something();

    return 0;
}

huangapple
  • 本文由 发表于 2023年6月5日 13:51:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76403786.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定