简体   繁体   English

C ++中的OOP类设计

[英]OOP class design in C++

I have simple question about class design in C++. 我对C ++中的类设计有一个简单的问题。

Lets assume we have the following class: 让我们假设我们有以下类:

class DataBase
{
    public:
        DataBase();


        void addEntry(const std::string& key, double value);
        double getEntry(const std::string& key);

    protected:
        std::map<std::string, double> table;
};

There is another class which holds a pointer to an instance of DataBase class: 还有另一个类,它包含一个指向DataBase类实例的指针:

class SomeClass
{
    protected:
        DataBase *someDataBase;
};

Here I get confused, as two options come to my mind: 在这里我感到困惑,因为我想到了两个选择:

  1. Each instance of SomeClass will have a database of its own. SomeClass每个实例都有自己的数据库。 In the sense that only the data added by this instance will be present in this database (dedicated databases). 在这个意义上,只有这个实例添加的数据才会出现在这个数据库中(专用数据库)。
  2. Each instance of SomeClass will be referring to a central database. SomeClass每个实例都将引用一个中央数据库。 Data added by any of the instances of SomeClass will be in one single database (a global database). SomeClass的任何实例添加的数据将位于单个数据库(全局数据库)中。

Question: 题:

  • What is the name of the aforementioned concepts in OOP? OOP中上述概念的名称是什么?
  • How each of the aforementioned approaches can be achieved in C++ 如何在C ++中实现上述每种方法
  1. Composition 组成
  2. Dependency injection 依赖注入

With Composition you can just have the DataBase as a member: 使用Composition,您可以将DataBase作为成员:

class SomeClass
{
    protected:
        DataBase someDataBase;
};

With Dependency injection you basically give SomeClass a pointer to your shared DataBase and SomeClass saves a pointer to it. 使用Dependency注入,您基本上可以为SomeClass一个指向共享DataBase的指针, SomeClass保存指向它的指针。 Be careful if you have a multithreaded application, you need to protect writing to the database and maybe reading as well. 如果你有一个多线程应用程序,要小心,你需要保护写入数据库,也许还要阅读。

class SomeClass
{
    public:
    SomeClass(DataBase* db) : someDataBase(db) {}

    protected:
        DataBase* someDataBase;
};

How you crate and where you store the shared DataBase is up to you. 您如何创建共享DataBase以及存储共享DataBase位置取决于您。

What you are looking for is the topic of ownership in C++. 您正在寻找的是C ++中的所有权主题。 When I say ownership, I mean who is responsible for managing the memory that holds the object. 当我说所有权时,我指的是谁负责管理持有该对象的内存。

In your first example each SomeClass could own its own DataBase . 在您的第一个示例中,每个SomeClass 都可以拥有自己的DataBase

class SomeClass
{
    private DataBase *db;
    public SomeClass();
    public SomeClass(DataBase* db);
    public ~SomeClass();
}

SomeClass::SomeClass()
{
    this.db = new DataBase();
}    

SomeClass::SomeClass(DataBase* db)
{
    this.db = db;
}

SomeClass::~SomeClass()
{
    delete this.db;
}

This SomeClass either takes ownership of the DataBase given to it or creates its own (practically you usually do one or the other). 这个SomeClass要么获得给它的DataBase的所有权,要么创建它自己的(实际上你通常做一个或另一个)。 This means you can pass in a DataBase object (using a concept known as dependency injection): 这意味着您可以传入DataBase对象(使用称为依赖注入的概念):

DataBase *db = new DataBase();
SomeClass sc(db);
sc.doSomeStuffWithDB();

or just let the class create the DataBase object: 或者只是让类创建DataBase对象:

SomeClass sc();
sc.doSomeStuffWithDB();

In the above example you don't have to worry about disposal of the DataBase objects, knowing that SomeClass should take care of disposal in its destructor. 在上面的示例中,您不必担心DataBase对象的处理,因为知道SomeClass应该在其析构函数中处理。

In the other scenario you could share a DataBase without having it be disposed of by your SomeClass (whether it's global or not is irrelevant). 在另一种情况下,您可以共享DataBase而不必由SomeClass它(无论它是全局的还是不相关的)。

class SomeClass
{
    private DataBase *db;
    public SomeClass(DataBase* db);
}

SomeClass::SomeClass(DataBase* db)
{
    this.db = db;
}

Here we could pass multiple SomeClass objects the same DataBase and not have to worry about them being disposed of by any of the objects. 在这里,我们可以将多个SomeClass对象传递给同一个DataBase ,而不必担心它们被任何对象处理掉。

DataBase *db = new DataBase();
SomeClass *sc1 = new SomeClass(db);
SomeClass *sc2 = new SomeClass(db);
sc1.doSomeStuffWithDB();
delete sc1;
sc2.doSomeStuffWithDB();
delete sc2;
delete db;

In this scenario we were able to reuse the DataBase object before disposing of it external to our SomeClass objects. 在这种情况下,我们能够在将SomeClass对象外部处理之前重用DataBase对象。 Practically speaking, this disposal could be managed by another class like DataBaseStore , allowing you to have a reliable way to handle and reuse DataBase objects. 实际上,这种处理可以由另一个类(如DataBaseStore管理,允许您以可靠的方式处理和重用DataBase对象。

Concept n°1 is composition. 概念n°1是组合物。 The Database is part of the SomeClass . DatabaseSomeClass一部分。
Concept n°2 doesn't have a name as far as I know. 据我所知,概念n°2没有名称。

Implementing concept n°1 : 实施概念1:

This is actually pretty straightworward : give SomeClass a member of type Database . 这实际上是非常直接的:给SomeClass一个Database类型的成员。

class SomeClass
{
    protected:
        DataBase someDataBase;
};

If you need pointers (eg for polymorphism), use a std::unique_ptr : 如果需要指针(例如,对于多态),请使用std::unique_ptr

class SomeClass
{
    protected:
        std::unique_ptr<DataBase> someDataBase;
};

Implementing concept n°2 : 实施概念2:

This depends on the rest of the program. 这取决于程序的其余部分。 If you can, the simplest way is to have a static Database member inside SomeClass : 如果可以,最简单的方法是在SomeClass有一个静态Database成员:

class SomeClass
{
    protected:
        static DataBase someDataBase;
// or   static std::unique_ptr<DataBase> someDataBase;
};

If Database can't be statically initialized, or if you don't want all of the SomeClass es to share the same Database , you can make use of the object factory pattern : 如果无法静态初始化Database ,或者您不希望所有 SomeClass es共享同一个Database ,则可以使用对象工厂模式:

class SomeClassFactory {
        // Constructors, etc

        SomeClass createSomeClass(/* args */) {
            return SomeClass(_database, /* args */);
        }

    private:
        Database _database;
// or   std::unique_ptr<Database> _database;
};

class SomeClass {
        friend class SomeClassFactory;

        // Private, only the factory can create SomeClass'es
        SomeClass(Database &database, /* args */)
        : database(database) {}

    protected:
        Database &database;
};

Then all SomeClass es created by the same factory will share the same Database . 然后,同一工厂创建的所有SomeClass将共享同一个Database

1 is object composition. 1是对象组成。

2 needs another Database* declaration in SomeClass declaration, and both pointers must be initialized. 2需要SomeClass声明中的另一个Database *声明,并且必须初始化两个指针。

I don't know whether the concept itself has a name, but the members are referred to as static or non-static . 我不知道概念本身是否有名称,但成员被称为静态 或非静态
Your 1. would be non-static and your 2. would be static . 你的1.是非静态的 ,你的2.将是静态的

As for how to implement this, you seem to know how to go about the non-static variant, and for the static one, just use the static keyword in the member declaration: 至于如何实现这一点,你似乎知道如何去做非静态变量,对于静态变量,只需在成员声明中使用static关键字:

class SomeClass
{
    protected:
        static DataBase *someDataBase;
};

Static members can be accessed with :: , like SomeClass::someDataBase . 可以使用::来访问静态成员,例如SomeClass::someDataBase

Initializing static members in C++ is not that straightforward though, see this question . 尽管如此,在C ++中初始化静态成员并不是那么简单,请参阅此问题

I will address both of your options: 我会解决你的两个选择:

  1. You have that with your current setup. 你有当前的设置。 Each instance of SomeClass will have a pointer to a DataBase class. SomeClass每个实例都有一个指向DataBase类的指针。

  2. In order to achieve this, you have to take DataBase out of your SomeClass , since SomeClass no longer owns the database. 为了实现这一点,你必须采取DataBase出你的SomeClass ,因为SomeClass不再拥有数据库。 You will utilize the singleton design pattern for your DataBase class to say "there is only one instance of this class at any one time". 您将使用DataBase类的单例设计模式来说“任何时候只有该类的一个实例”。

To do that, you will write your database class like so: 为此,您将编写数据库类,如下所示:

class DataBase
{
    public:
        DataBase();
        static Database * instance(); // This is the function that is used to get the global database for use.

        void addEntry(const std::string& key, double value);
        double getEntry(const std::string& key);

    protected:
        std::map<std::string, double> table;
    private:
        static DataBase * pDataBase;
};

To implement the instance() method: 要实现instance()方法:

static DataBase * DataBase::instance()
{
    if (!pDataBase)
        pDataBase = new DataBase();

    return pDataBase;
}

If you would like more information on singletons, read to your heart's content here . 如果您想了解有关单身人士的更多信息,请在此处阅读您的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM