代码之家  ›  专栏  ›  技术社区  ›  Niello

从C中的另一个对象初始化对象++

  •  2
  • Niello  · 技术社区  · 9 年前

    在我的项目中,我有可以从不同格式加载和重新加载的资源对象。加载算法在不同的ResourceLoader子类中实现。

    class Resource
    {
    private:
    
        // Not for client access    
        Type1 InternalData1;
        Type2 InternalData2;
        TypeN InternalDataN;
    
        ResourceLoader Loader;
    
    public:
    
        // Any client interface
        void UseResource();
    };
    
    class ResourceLoader
    {
    public:
    
        void Load(Resource& R) = 0;
    };
    
    class ResourceLoaderFormat1: public ResourceLoader
    {
    public:
    
        void Load(Resource& R) { ...loads Resource from Format1... }
    };    
    
    class ResourceLoaderFormat2: public ResourceLoader
    {
    public:
    
        void Load(Resource& R) { ...loads Resource from Format2... }
    };
    

    加载器读取给定格式的输入并初始化其目标资源对象R。加载器存储在资源中,因此如果资源无效,它将使用存储的加载器重新加载自身。

    问题是加载器应该如何初始化资源?

    1. 公开所有InternalData字段。它允许客户端访问它们,这是不好的。
    2. 让Loader成为Resource的朋友。特定格式的每个新加载器都将被添加到资源头中,这会扼杀可扩展性,并要求任何编写扩展的程序员接触基本代码。
    3. 为每个InternalData提供setter。离公开这些数据不远了,因为任何客户都可能更改数据,所以不能更改。
    4. 提供资源::Setup(InternalData1、InternalData2、InternalData N),或者将它们全部封装在某个结构中并传递该结构。除了一次设置所有字段之外,与3相同。

    问题是,Resource类字段必须可从可扩展的类集进行写入,并且必须不可从客户端代码进行写入。有什么好的OOP解决方案吗?谢谢

    2 回复  |  直到 9 年前
        1
  •  1
  •   Ami Tavory    9 年前

    假设我们选择

    让Loader成为Resource的朋友。

    有退税

    特定格式的每个新加载器都将被添加到资源头中,这会扼杀可扩展性,并要求任何编写扩展的程序员接触基本代码。


    但是,由于您将加载器拆分为基类+派生类,因此您可以只授予对 Loader ,并给予 装载机 通过子类访问 protected 成员。

    class Resource
    {
        Type1 InternalData1;
        ...
        friend class ResourceLoader;
    };
    
    class ResourceLoader
    {
        ...
    protected:
        static void setResourceInternalData1(Resource &r, const Type1 &val1);
        ...
    };
    

    全部的 ResourceLoader 子类现在可以访问这些setter,因为它们是 受保护的 :

    class ResourceLoaderFormat1: public ResourceLoader;
    class ResourceLoaderFormat2: public ResourceLoader;
    

    只要不更改 Resource 太频繁了。

        2
  •  1
  •   Garf365 Sean Breen    9 年前

    另一个解决方案是(如我的第一条评论所述):

    class ResourceClient
    {
        public:
            virtual void UseResource() = 0;
    }
    class ResourceLoader
    {
        public:
             virtual void SetResource() = 0;
    }
    class Resource:
        public ResourceClient,
        public ResourceLoader
    {
    private:
    
        // Not for client access    
        Type1 InternalData1;
        Type2 InternalData2;
        TypeN InternalDataN;
    
        ResourceLoader Loader;
    
    public:
    
        // Any client interface
        virtual void UseResource();
        virtual void SetResource();
    };
    
    class ResourceLoader
    {
    public:
    
        void Load(ResourceLoader& R) = 0;
    };
    
    class ResourceLoaderFormat1: public ResourceLoader
    {
    public:
    
        void Load(ResourceLoader& R) { ...loads Resource from Format1... }
    };    
    
    class ResourceLoaderFormat2: public ResourceLoader
    {
    public:
    
        void Load(ResourceLoader& R) { ...loads Resource from Format2... }
    };
    

    需要写入Resource的函数集使用ResourceLoader指针,而重新连接的函数将使用ResourceClient指针访问资源。

    这个解决方案的优点是,您不需要使用写访问来声明任何类或函数的朋友。根据您想要做的事情或功能能够做的事情,使用正确的界面