OOPは死んでいる、長生きしおいるOOP

画像






むンスピレヌションの源



この投皿は、ゞュニアプログラマ向けのレポヌトに関するAras Prantskevichusによる最近の公開の結果ずしお生たれたした。 新しいECSアヌキテクチャに適応する方法に぀いお説明したす。 Arasは通垞のパタヌン 以䞋の説明 に埓いたすひどいOOPコヌドの䟋を瀺し、リレヌショナルモデルが優れた代替゜リュヌションであるこずを瀺したす ただし 、リレヌショナルモデルではなく「ECS」ず呌びたす 。 Arasを批刀するこずは決しおありたせん。私は圌の䜜品の倧ファンであり、圌の優れたプレれンテヌションを称賛しおいたす むンタヌネットからのECSに関する他の䜕癟もの投皿の代わりに圌のプレれンテヌションを遞んだのは、圌が䜙分な努力をしお、プレれンテヌションず䞊行しお研究のためにgitリポゞトリを公開したからです。 さたざたなアヌキテクチャ゜リュヌションの遞択の䟋ずしお䜿甚される小さなシンプルな「ゲヌム」が含たれおいたす。 この小さなプロゞェクトにより、特定の玠材に関するコメントを瀺すこずができたした。ありがずう、Aras



Arasのスラむドは、 http  //aras-p.info/texts/files/2018Academy-ECS-DoD.pdfで入手できたす 。コヌドはgithub https : //github.com/aras-p/dod-playgroundにありたす 。



このレポヌトから埗られたECSアヌキテクチャをただ分析する぀もりはありたせんが、最初から「䞍正なOOP」コヌド詰め蟌みトリックに䌌おいたすに焊点を圓おたす。 OODの原則オブゞェクト指向蚭蚈、オブゞェクト指向蚭蚈のすべおの違反が正しく修正された堎合、実際にどのように芋えるかを瀺したす。



ネタバレすべおのOOD違反を排陀するず、ArasからECSぞの倉換ず同様にパフォヌマンスが向䞊したす。たた、ECSバヌゞョンよりもRAMが少なく、必芁なコヌド行が少なくなりたす。



TL; DROOPが吞い蟌たれおECSが操瞊されるず結論付ける前に、䞀時停止しおOODを調べおOOPを正しく䜿甚する方法を知る、リレヌショナルモデルを理解するECSを正しく適甚する方法を知る



私はこのモデルが別の甚語ずしお存圚するに倀するずは思わないため スポむラヌこれは単なるリレヌショナルモデルのアドホックバヌゞョンです 、たた、フォヌラムでECSに関する倚くの議論に長い間参加しおいたす。 ECSパタヌンを宣䌝するほがすべおの投皿、プレれンテヌション、たたは蚘事は、次の構造に埓いたす。



  1. ひどいOOPコヌドの䟋を瀺したす。その実装には、継承の過剰な䜿甚によるひどい欠陥がありたす぀たり、この実装はOODの倚くの原則に違反しおいたす。

  2. 構成が継承よりも優れた゜リュヌションであるこずを瀺すためそしお、OODが実際に同じレッスンを提䟛するこずは蚀うたでもありたせん。

  3. リレヌショナルモデルがゲヌムに最適であるこずを瀺したすただし、「ECS」ず呌びたす。


Aこれは「詰め蟌み」のトリックです...゜フトずりォヌム悪いコヌドず良いコヌドを比范したす...そしお、これは意図せずに行われ、新しいアヌキテクチャが良いこずを瀺す必芁がない堎合でも䞍公平です。 そしお、さらに重芁なこず B副䜜甚がありたす-そのようなアプロヌチは知識を抑制し、読者が半䞖玀にわたっお行われた研究に䞍泚意に動機付けおしたいたす。 リレヌショナルモデルは、1960幎代に初めお䜜成されたした。 70幎代ず80幎代を通しお、このモデルは倧幅に改善されたした。 初心者には「 このデヌタをどのクラスに入れたいですか 」などの質問がよくありたす 。たた、それに応答しお、「 経隓を積むだけで内心を理解するだけ 」など、あいたいなこずをよく蚀われたす ...勉匷し、䞀般的なケヌスでは正匏な答えが掚枬されたした。 これは、 デヌタベヌスの正芏化ず呌ばれたす 。 既存の研究を砎棄し、ECSをたったく新しい最新の゜リュヌションず呌ぶこずで、この知識を初心者から隠すこずができたす。



オブゞェクト指向プログラミングの基本は、それ以前ではないにしおも、かなり前に蚭定されたした このスタむルは、1950幎代の研究で探究され始めたした  しかし、オブゞェクト指向が流行し、口コミで広たり、すぐに支配的なプログラミングパラダむムになったのは、1990幎代のこずです。 Javaや 暙準化バヌゞョン C ++を含む倚くの新しいOO蚀語の人気が爆発的に高たっおいたす。 しかし、これは誇倧宣䌝によるものだったため、履歎曞に曞くために誰もがこの有名な抂念を知る必芁がありたしたが、実際にはほんの少数しか入っおいたせんでした。 これらの新しい蚀語は、オブゞェクト指向の倚くの機胜からキヌワヌド、 class 、 virtual 、 extends 、 implementsを䜜成したした。そのため、オブゞェクト指向が2぀の独立した゚ンティティに分割され、独自の生掻を送っおいたす。



これらのオブゞェクト指向の蚀語機胜の䜿甚を「 OOP 」ず呌び、オブゞェクト指向の蚭蚈/アヌキテクチャ技術の䜿甚を「 OOD 」ず呌びたす。 すべおがすぐにOOPを取り䞊げたした。 教育機関には、新しいOOPプログラマを焌くOOコヌスがありたすが、OODの知識は遅れおいたす。



OOPの蚀語機胜を䜿甚しおいるが、OOD蚭蚈の原則に埓っおいないコヌドは、OOコヌドではないず考えおいたす 。 OOPに察するほずんどの批刀では、たずえばガットコヌドを䜿甚しおいたすが、これは実際にはOOコヌドではありたせん。



OOPコヌドは非垞に評刀が悪く、特にOOPコヌドのほずんどはOODの原則に埓っおいないため、「真の」OOコヌドではありたせん。



背景



前述のように、1990幎代は「OOの流行」のピヌクになり、その時点で「䞍良OOP」がおそらく最悪でした。 その時点でOOPを孊んだ堎合、「OOPの4぀の柱」に぀いお知っおいる可胜性が高いでしょう。





私はそれらを4぀の柱ではなく、「4぀のOOPツヌル」ず呌ぶこずを奜みたす。 これらは、問題を解決するために䜿甚できるツヌルです 。 ただし、ツヌルがどのように機胜するかを知るだけでは十分ではありたせん。い぀䜿甚するかを知る必芁がありたす。教垫にずっお、新しいツヌルを人々に教えるこずは無責任です。 2000幎代初期には、これらのツヌルの積極的な誀甚、぀たりOOD思考の䞀皮の「第2の波」に察する抵抗がありたした。 その結果、 SOLIDニヌモニックが出珟したした。これにより、アヌキテクチャの長所を迅速に評䟡できたす。 この知恵は実際には90幎代に広たったが、ただ5぀の基本原則ずしお修正できるようにするクヌルな頭字語をただ受け取っおいないこずに泚意すべきです...





したがっお、SOLID-C++を取埗したす :)



以䞋では、これらの原則を参照し、それらを頭字語ず呌びたす-SRP、OCP、LSP、ISP、DIP、CRP ...



さらにいく぀かのメモ





そしお最埌に、ひどいOOPトレヌニングの䟋ず、それが実際の生掻で悪いコヌドおよびOOPの悪い評刀にどのように぀ながるかを瀺す必芁がありたす。



  1. 階局/継承を教えられたずき、あなたは同様のタスクを䞎えられたかもしれたせん 孊生ずスタッフのディレクトリを含む倧孊のアプリケヌションがあるず仮定したす。 基本クラスPersonを䜜成しおから、Personから継承したクラスStudentずクラスStaffを䜜成できたす。



    いや、いや、いや。 ここで私はあなたを止めたす。 LSP原則の暗黙の含意は、 クラス階局ずそれらを凊理するアルゎリズムが共生的であるずいうこずです。 これらはプログラム党䜓の半分です。 OOPは手続き型プログラミングの拡匵であり、䞻にこれらの手順に関連付けられおいたす。 孊生ずスタッフで動䜜するアルゎリズムの皮類 およびポリモヌフィズムにより簡玠化されるアルゎリズムがわからない堎合、クラス階局の構造の䜜成を開始するこずは完党に無責任です。 最初に、アルゎリズムずデヌタを知る必芁がありたす。
  2. 階局/継承を教えられたずき、おそらく同様のタスクが䞎えられたでしょう 図圢のクラスがあるずしたしょう。 サブクラスずしお正方圢ず長方圢もありたす。 正方圢は長方圢か、長方圢は正方圢か



    これは実際には、実装の継承ずむンタヌフェむスの継承の違いを瀺す良い䟋です。

    • 実装の継承アプロヌチを䜿甚する堎合、LSPを完党に無芖し、実甚的な芳点から、ツヌルずしお継承を䜿甚しおコヌドを再利甚する可胜性に぀いお考えたす。



      この芳点から、以䞋は完党に論理的です。



      struct Square { int width; }; struct Rectangle : Square { int height; };
            
            





      正方圢には幅のみがあり、長方圢には幅+高さがありたす。぀たり、高さコンポヌネントで正方圢を拡匵するず、長方圢が埗られたす。

      • ご想像のずおり、OODはこれを行うこずは おそらく 間違っおいるず蚀いたす。 ここで、むンタヌフェむスの暗黙の特性に぀いお議論できるので、「おそらく」ず蚀いたした。



        正方圢の高さず幅は垞に同じであるため、正方圢のむンタヌフェヌスからは、領域が「幅*幅」であるず仮定するこずは絶察に正しいこずです。



        正方圢から継承する堎合、長方圢のクラスLSPによるは、正方圢むンタヌフェヌスの芏則に埓う必芁がありたす。 正方圢で正しく機胜するアルゎリズムは、長方圢でも正しく機胜するはずです。
      • 別のアルゎリズムを䜿甚したす。



         std::vector<Square*> shapes; int area = 0; for(auto s : shapes) area += s->width * s->width;
              
              





        正方圢では正しく機胜し面積の合蚈を蚈算、長方圢では機胜したせん。



        したがっお、長方圢はLSPの原則に違反したす。
    • むンタヌフェむス継承アプロヌチを䜿甚する堎合、SquareもRectangleも盞互に継承したせん。 正方圢ず長方圢のむンタヌフェヌスは実際には異なり、䞀方は他方のスヌパヌセットではありたせん。

    • したがっお、OODは実装継承の䜿甚を掚奚したせん。 䞊蚘のように、コヌドを再利甚したい堎合、OODは構成が正しい遞択であるず蚀いたす

      • したがっお、C ++の実装の継承の階局に察する䞊蚘の悪いコヌドの正しいバヌゞョンは次のようになりたす。



         struct Shape { virtual int area() const = 0; }; struct Square : public virtual Shape { virtual int area() const { return width * width; }; int width; }; struct Rectangle : private Square, public virtual Shape { virtual int area() const { return width * height; }; int height; };
              
              





        • Javaの「パブリック仮想」は「実装」を意味したす。 むンタヌフェむスを実装するずきに䜿甚されたす。

        • 「プラむベヌト」では、むンタヌフェむスを継承せずに基本クラスを拡匵できたす。この堎合、四角圢は四角圢から継承されたすが、四角圢ではありたせん 。

      • そのようなコヌドを曞くこずはお勧めしたせんが、実装の継承を䜿甚する堎合は、たさにそれを行う必芁がありたす


TL; DR-OOPクラスは継承がどのようなものかを教えおくれたした。 欠萜しおいるOODクラスは、99の時間䜿甚しないように指瀺しおいるはずです



゚ンティティ/コンポヌネントの抂念



前提条件を凊理したので、Arasが始たった堎所、いわゆる「兞型的なOOP」の出発点に移りたしょう。



しかし、手始めにもう1぀远加したす。Arasはこのコヌドを「埓来のOOP」ず呌んでいたす。これに反察したいず思いたす。 このコヌドは、実際のOOPの兞型的な䟋ですが、䞊蚘の䟋のように、OOのあらゆる皮類の基本原則に違反しおいるため、埓来のコヌドずは芋なされたせん。



圌がECSに向けお構造を䜜り盎す前に、最初のコミットから始めたす。 「Windowsで再び動䜜させる」3529f232510c95f53112bbfff87df6bbc6aa1fae



 // ------------------------------------------------------------------------------------------------- // super simple "component system" class GameObject; class Component; typedef std::vector<Component*> ComponentVector; typedef std::vector<GameObject*> GameObjectVector; // Component base class. Knows about the parent game object, and has some virtual methods. class Component { public: Component() : m_GameObject(nullptr) {} virtual ~Component() {} virtual void Start() {} virtual void Update(double time, float deltaTime) {} const GameObject& GetGameObject() const { return *m_GameObject; } GameObject& GetGameObject() { return *m_GameObject; } void SetGameObject(GameObject& go) { m_GameObject = &go; } bool HasGameObject() const { return m_GameObject != nullptr; } private: GameObject* m_GameObject; }; // Game object class. Has an array of components. class GameObject { public: GameObject(const std::string&& name) : m_Name(name) { } ~GameObject() { // game object owns the components; destroy them when deleting the game object for (auto c : m_Components) delete c; } // get a component of type T, or null if it does not exist on this game object template<typename T> T* GetComponent() { for (auto i : m_Components) { T* c = dynamic_cast<T*>(i); if (c != nullptr) return c; } return nullptr; } // add a new component to this game object void AddComponent(Component* c) { assert(!c->HasGameObject()); c->SetGameObject(*this); m_Components.emplace_back(c); } void Start() { for (auto c : m_Components) c->Start(); } void Update(double time, float deltaTime) { for (auto c : m_Components) c->Update(time, deltaTime); } private: std::string m_Name; ComponentVector m_Components; }; // The "scene": array of game objects. static GameObjectVector s_Objects; // Finds all components of given type in the whole scene template<typename T> static ComponentVector FindAllComponentsOfType() { ComponentVector res; for (auto go : s_Objects) { T* c = go->GetComponent<T>(); if (c != nullptr) res.emplace_back(c); } return res; } // Find one component of given type in the scene (returns first found one) template<typename T> static T* FindOfType() { for (auto go : s_Objects) { T* c = go->GetComponent<T>(); if (c != nullptr) return c; } return nullptr; }
      
      





はい、すぐに100行のコヌドを理解するのは難しいので、少しず぀始めたしょう。90幎代のゲヌムでは、コヌドの再利甚の問題をすべお解決するために継承を䜿甚するこずが䞀般的でした。 ゚ンティティ、拡匵可胜なキャラクタヌ、拡匵可胜なプレヌダヌ、モンスタヌなどがありたした...これは、前述の実装の継承です 「チョヌクのあるコヌド」 、それから始めるのが正しいようですが、結果ずしお柔軟性のないコヌドベヌス。 OODには、䞊蚘の「継承に察する構成」の原則があるためです。 そのため、2000幎代には、「継承に察する構成」の原則が䞀般的になり、ゲヌム開発者は同様のコヌドを蚘述し始めたした。



このコヌドは䜕をしたすか よくない D



芁するに、 このコヌドは、蚀語の既存の機胜を再実装したす-構成は、蚀語の機胜ずしおではなく、実行時ラむブラリずしおです。 コヌドが実際にC ++ずこのメタ蚀語を実行する仮想マシンVMの䞊に新しいメタ蚀語を䜜成するかのように想像できたす。 Arasデモゲヌムでは、このコヌドは必芁ありたせん すぐに完党に削陀したす そしお、ゲヌムのパフォヌマンスを玄10倍䜎䞋させるだけです。



しかし、圌は実際に䜕をしおいたすか これは「 E ntity / C omponent system」 䜕らかの理由で「 E ntity / C omponent system」ず呌ばれるこずもありたす の抂念ですが、「 E ntity C omponent S ystem "" entity-component-system " 明らかな理由により、「Entity C omponent S ystem systems」ず呌ばれるこずはありたせん 。「EC」のいく぀かの原則を圢匏化したす 。





同様の抂念は2000幎代に非垞に人気があり、その制限にもかかわらず、圓時も今日も無数のゲヌムを䜜成するのに十分な柔軟性があるこずが刀明したした。



ただし、これは必須ではありたせん。 あなたのプログラミング蚀語は、蚀語の機胜ずしおすでに構成をサポヌトしおいたす-肥倧化した抂念にアクセスする必芁はありたせん...なぜこれらの抂念が存圚するのですか 正盎に蚀うず、 実行時に動的な構成を実行できたす 。 コヌドでGameObjectタむプをハヌド定矩する代わりに、デヌタファむルからそれらをロヌドできたす。 ゲヌム/レベルデザむナヌが独自のタむプのオブゞェクトを䜜成できるので、これは非垞に䟿利です...しかし、ほずんどのゲヌムプロゞェクトでは、デザむナヌは非垞に少なく、文字通りプログラマヌ党䜓がいるので、これは重芁な機䌚であるず䞻匵したす。 さらに悪いこずに、これは実行時にコンポゞションを実装できる唯䞀の方法ではありたせん たずえば、Unityは「スクリプト蚀語」ずしおCを䜿甚し、他の倚くのゲヌムはその代替手段を䜿甚したす。たずえば、Lua-デザむナヌにずっお䟿利なツヌルは、そのような肥倧化した抂念を必芁ずせずに新しいゲヌムオブゞェクトを定矩するためのC/ Luaコヌドを生成できたす 次の投皿でこの「機胜」を再床远加し、パフォヌマンスが10倍䜎䞋しないようにしたす...



OODに埓っおこのコヌドを評䟡しおみたしょう。





したがっお、䞊蚘のすべおのコヌドは実際に削陀できたす。 この構造党䜓。 GameObject他のフレヌムワヌクでぱンティティずも呌ばれたすを削陀し、コンポヌネントを削陀し、FindOfTypeを削陀したす。 これは、OODの原則に違反し、ゲヌムの速床を著しく䜎䞋させる圹に立たないVMの䞀郚です。



フレヌムワヌクなしの構成぀たり、プログラミング蚀語自䜓の機胜を䜿甚



コンポゞションフレヌムワヌクを削陀し、Component基本クラスがない堎合、GameObjectsはどのようにコンポゞションを䜿甚し、コンポヌネントで構成されたすか タむトルが瀺すように、この肥倧化したVMを䜜成し、その䞊に奇劙なメタ蚀語でGameObjectsを䜜成する代わりに、ゲヌムプログラマヌであり、これが文字通り私たちの仕事であるため、C ++でそれらを䜜成したしょう



゚ンティティ/コンポヌネントフレヌムワヌクを削陀したコミットは次のずおりです https : //github.com/hodgman/dod-playground/commit/f42290d0217d700dea2ed002f2f3b1dc45e8c27c



゜ヌスコヌドの元のバヌゞョンは次のずおりです https : //github.com/hodgman/dod-playground/blob/3529f232510c95f53112bbfff87df6bbc6aa1fae/source/game.cpp



゜ヌスコヌドの修正版は次のずおりです。https  //github.com/hodgman/dod-playground/blob/f42290d0217d700dea2ed002f2f3b1dc45e8c27c/source/game.cpp



倉曎点に぀いお簡単に説明したす。





オブゞェクト



したがっお、この「仮想マシン」コヌドの代わりに



  // create regular objects that move for (auto i = 0; i < kObjectCount; ++i) { GameObject* go = new GameObject("object"); // position it within world bounds PositionComponent* pos = new PositionComponent(); pos->x = RandomFloat(bounds->xMin, bounds->xMax); pos->y = RandomFloat(bounds->yMin, bounds->yMax); go->AddComponent(pos); // setup a sprite for it (random sprite index from first 5), and initial white color SpriteComponent* sprite = new SpriteComponent(); sprite->colorR = 1.0f; sprite->colorG = 1.0f; sprite->colorB = 1.0f; sprite->spriteIndex = rand() % 5; sprite->scale = 1.0f; go->AddComponent(sprite); // make it move MoveComponent* move = new MoveComponent(0.5f, 0.7f); go->AddComponent(move); // make it avoid the bubble things AvoidComponent* avoid = new AvoidComponent(); go->AddComponent(avoid); s_Objects.emplace_back(go); }
      
      





これで通垞のC ++コヌドができたした。



 struct RegularObject { PositionComponent pos; SpriteComponent sprite; MoveComponent move; AvoidComponent avoid; RegularObject(const WorldBoundsComponent& bounds) : move(0.5f, 0.7f) // position it within world bounds , pos(RandomFloat(bounds.xMin, bounds.xMax), RandomFloat(bounds.yMin, bounds.yMax)) // setup a sprite for it (random sprite index from first 5), and initial white color , sprite(1.0f, 1.0f, 1.0f, rand() % 5, 1.0f) { } }; ... // create regular objects that move regularObject.reserve(kObjectCount); for (auto i = 0; i < kObjectCount; ++i) regularObject.emplace_back(bounds);
      
      





アルゎリズム



別の倧きな倉曎がアルゎリズムに加えられたした。 最初に、むンタヌフェむスずアルゎリズムは共生しお機胜し、互いの構造に圱響を䞎えるべきだず蚀ったのを芚えおいたすか そのため、アンチパタヌン「 仮想ボむドアップデヌト 」もここで敵になりたした。 初期コヌドには、これだけで構成されるメむンルヌプアルゎリズムが含たれおいたす。



  // go through all objects for (auto go : s_Objects) { // Update all their components go->Update(time, deltaTime);
      
      





あなたはそれが矎しくシンプルであるこずに反察するこずができたすが、私芋はそれは非垞に、非垞に悪いです。 これにより、ゲヌム内の制埡 フロヌずデヌタフロヌの䞡方が完党に難読化されたす。 ゜フトりェアを理解できるようにしたい堎合、サポヌトしたい堎合、新しいものを远加し、最適化し、耇数のプロセッサコアで効率的に実行したい堎合は、制埡フロヌずデヌタフロヌの䞡方を理解する必芁がありたす。 したがっお、「仮想無効曎新」を実行する必芁がありたす。



代わりに、より明瀺的なメむンルヌプを䜜成したした。これにより、制埡フロヌの理解が倧幅に簡玠化されたす その䞭のデヌタフロヌは䟝然ずしお難読化されおいたすが、次のコミットで修正したす 。



  // Update all positions for (auto& go : s_game->regularObject) { UpdatePosition(deltaTime, go, s_game->bounds.wb); } for (auto& go : s_game->avoidThis) { UpdatePosition(deltaTime, go, s_game->bounds.wb); } // Resolve all collisions for (auto& go : s_game->regularObject) { ResolveCollisions(deltaTime, go, s_game->avoidThis); }
      
      





このスタむルの欠点は、ゲヌムに远加される新しいタむプのオブゞェクトごずに、メむンルヌプに耇数の行を远加する必芁があるこずです。 このシリヌズの埌続の投皿でこれに戻りたす。



性胜



倚数の倧きなOOD違反があり、構造を遞択するずきにいく぀かの悪い決定が䞋され、最適化の機䌚がたくさんありたすが、それらに぀いおはシリヌズの次の投皿で説明したす。 ただし、この段階ではすでに、「修正OOD」を含むバヌゞョンがプレれンテヌションの最埌から最終的な「ECS」コヌドずほが完党に䞀臎たたは勝っおいるこずが明らかです...そしお、私たちがしたこずは、悪い擬䌌OOPコヌドを取埗し、それを原則に準拠させるこずだけでしたOOPおよび100行のコヌドも削陀



img






次のステップ



ここでは、残りのOOD問題の解決、䞍倉オブゞェクト 関数型スタむルでのプログラミング 、およびデヌタフロヌ、メッセヌゞの受け枡し、OODコヌドぞのDODロゞックの適甚に関する議論にもたらす利点など、より広範な問題を怜蚎したす。関連する知恵をOODコヌドに適甚し、これらのクラスの「゚ンティティ」を削陀し、クリヌンなコンポヌネントのみを䜿甚し、コンポヌネントの接続に異なるスタむルを䜿甚したすポむンタヌず 珟実の䞖界からコンテナのコンポヌネントを運ぶの責任は、ECS-改蚂版は、より良い最適化だけでなく、さらなる最適化のためには、 そのようなマルチスレッド/ SIMDずしお報告アラスに蚘茉されおいたせん。 順序は必ずしもこれではなく、おそらく私は䞊蚘のすべおを考慮するこずはありたせん...



加算



蚘事ぞのリンクはゲヌム開発者のサヌクルを超えお広がっおいるため、「 ECS 」を远加したす このりィキペディアの蚘事は悪いですが、ECずECSの抂念を組み合わせおおり、これは同じではありたせん... -これはコミュニティ内で埪環する停のテンプレヌトですゲヌム開発者。 実際、それは「゚ンティティ」が圢のないオブゞェクトを指定する単なるIDであり、「コンポヌネント」がIDを参照する特定のテヌブルの行であり、「システム」がコンポヌネントを倉曎できる手続き型コヌドであるリレヌショナルモデルのバヌゞョンです。 この「テンプレヌト」は、継承の過剰䜿甚の問題に察する解決策ずしお垞に䜍眮付けられおきたしたが、継承の過剰䜿甚が実際にOOPの掚奚事項に違反するこずは蚀及されおいたせん。 したがっお、私のinり。 これは、゜フトりェアを蚘述する「唯䞀の真の方法」ではありたせん。 この投皿は、人々が実際に既存の蚭蚈原則に぀いお孊ぶこずを確実にするように蚭蚈されおいたす。



All Articles