web-dev-qa-db-ja.com

オブジェクト指向設計-ゲノムクラス/突然変異クラス

環境

NEAT (NeuroEvolution of Augmenting Topologies)と呼ばれるGenetic Algorithmの実装を開始する方法について、私の友人と議論しています。

方法1

Genome用とMutation用の2つのクラスを持つことを支持して、私は主張しています。この突然変異クラスは、ゲノムを入力として取り、突然変異したゲノムを返すことにより、ゲノムを突然変異させるためのメソッドを提供します。さらに、この実装には、各プロセス選択クロスオーバーなどのクラスがあります。

長所

  • このように、後でMutationクラスから派生して、さまざまな種類のミューテーションを実装するためのオプションがあります。
  • ユニットテストの改善にも役立つと思います。

短所

  • その他のクラス
  • 実生活をモデル化していません(たとえば、ゲノムのようにヒトできる歩くできる変異

方法2

私の友人は、このために1つのクラス、Genomeクラスのみを持ちたいと考えています。この実装では、mutateGenomeクラスのメソッドであり、変異したゲノムを出力として返します。

長所

  • これにより、複雑さが軽減されます。
  • human canwalkと同じように、ゲノム canmutateもモデル化します。
  • また、慣例に従います(すでに実装されているソリューションのコードを参照)。

短所

  • 懸念の分離が少ないため、単体テストが難しくなります。
  • さまざまな種類の突然変異を追加する必要がある場合、後で拡張するのは困難です。
2
Mohsin Bukhari

3つ目の選択肢があります。ゲノムはデータです。つまり、値のセマンティクスがあります。ただし、まずは長所と短所について説明します。


方法1

このように、後でMutationクラスから派生して、さまざまな種類のミューテーションを実装するオプションがあります。

Mutationクラスからの派生について考えているという考えは、GenomeオブジェクトにMutationオブジェクトを取得することを示唆しています(Mutationクラスまたは派生オブジェクトのオブジェクトを渡すことを強制します)。

では、何が入ってるの? GenomeクラスはデータをMutationクラスに渡すことができるため、新しいインスタンスのデータが作成され、次にGenomeクラスがそれを作成します。さて、あなたがそうしているなら、ゲノムと突然変異は密接に結びついています。

ここで、インターフェースIMutationのほうが優れているでしょうか?たぶん。ただし、問題の原因は異なる変異を作成することではありませんが、変異はGenome内のデータに作用する必要があるということです。 Mutation(またはIMutation)を変更せずに、ゲノムの実装の詳細を変更するのは難しい場合があります。

ユニットテストの改善にも役立つと思います。

単体テストにはインターフェースの方が適しています。

その他のクラス

クラスの数を気にする必要はありません。 単一責任の原則 と結合について心配します。

より多くのクラスが必要な場合は、そうしてください。

実生活をモデル化していません(たとえば、人間はゲノムが変異できるように歩くことができます)

それはそれほど重要ではないと私は主張します。

それは、近代化された現実が役に立たないということではありません。これは便利です。コードを理解しやすくし、保守を容易にします。ただし、現実をモデル化することがメンテナンスにとって逆効果になる場合は、現実を心配することをやめてください。


方法2

これにより、複雑さが軽減されます。

間違いなく、はい。可動部品が少ないほど、複雑さが少なくなります。また、テストと保守が困難になることもあります。この場合でも、私はそれをプロとして数えます。

また、人間が歩くことができるのと同じように、ゲノムが変異できることもモデル化します。

これはより哲学的な議論です:あなたはゲノムに代理人を割り当てています。彼らは生きていますか?

じゃあ、行かないで。コンピュータサイエンスの観点から見ると、ゲノムは属性のリストです。たとえば、車の設計を進化させるために遺伝的アルゴリズムを使用する場合、それは現実をモデル化するものではありません。

その上...現実をモデル化することは、それほど重要ではありません。

また、慣例に従います(すでに実装されているソリューションのコードを参照)。

それには理由があります。突然変異はゲノムのデータにアクセスする必要があります。変異コードをゲノムクラスに配置する場合、カプセル化を解除したり、クラスを密結合したりする必要はありません。

OOP方法です。OOPに固執することが目的の場合は、この方法に従ってください。


私が提案した3番目の方法

ゲノムを価値のある意味論を持つタイプにします。可能であれば、遺伝的アルゴリズムをテンプレート/ジェネリック型として実装します。 TGenomeIMutation<TGenome>またはそのようなものが必要です...

アルゴリズムを実行するクラスを用意します。ゲノムがどのように表されているかを知る必要はありません。それをMutationで初期化します。 戦略パターン と考えてください。さまざまな種類のゲノムで機能する突然変異を実装できます。

テストは簡単です。コードは完全に分離されています。

実際、強制できる場合は、ゲノムを変更できないようにしてください。 (それは不変です)。突然変異は実際にコピーを作成します。 「ImperfectClonation」になります。インターフェースを使用する以外に、不変タイプを使用すると、テストに役立ちます。

カプセル化?見て:オブジェクトは考え方です。彼らは現実をモデル化するのに最適です。ただし、それが仕事に最適なツールではない場合もあります。真実がなければ、他のプログラミングパラダイムは成功できません。

値型には、オブジェクト一般にはない他の利点があります。それらの1つは、システム間での移動の容易さです。ネットワーク経由で送信したり、永続的なストレージにコミットしたりするのは簡単です。

ライブラリを作成している場合、開発者が遺伝的アルゴリズムを実行するために必要な属性の種類はわかりません。このオプションは、その汎用性を提供します。

しかし、それについて考えます。おそらくTGenomeではなくTGene[]です。

1
Theraot

アプローチ1では、さまざまな種類の変異をサポートするための戦略パターンを適用できます。

[短所]より多くのクラス

これは実際にはマイナス面ではありません。クラスはインスタンスメンバーを編成します。どちらのアプローチでも、おそらく同じ数のインスタンスメンバーがあります。概念の融合を犠牲にして、クラスを最小化しようとするべきではありません。

[短所]実生活をモデル化しない(たとえば、ゲノムが変異するように人間は歩くことができる)

通常、クラスを使用して「実際の生活をモデル化」しようとはしません。システム全体で目的の概念、その関係と動作をモデル化しようとしますが、実際のクラスを1対1でモデル化しないでください。一部のプログラミング言語は多重継承をサポートしていませんが、「実際の」生物学はサポートしています(つまり、 2つの親)、それでも、これらのプログラミング言語を使用するために必要なすべてのものをモデル化できます。


アプローチ2では、サブクラスを適用してミューテーションの動作をオーバーライドできます。これは、ゲノムのインスタンスとその突然変異の間に「is-a」関係があることを示唆しています。ほとんどの言語ではインスタンスのクラスを変更できないため、別の突然変異を適用するには、ゲノムを別のクラスに複製する必要があります。 (これは実行可能ですが、不要な複雑さのように見えます。)

[長所]これにより、複雑さを軽減できます。

ソフトウェアのすべてが1つのクラスでのみ実行できますが、これにより複雑さが軽減されるわけではありません。

[プロ]人間が歩くのと同じように、ゲノムが変異することもモデル化します。

ゲノムを変異させる必要があるが、必ずしも自己変異ゲノムを必要としない。


寿命も考えてみましょう。ゲノムクラスの有用性/有用性は、おそらく突然変異とは無関係です。突然変異は一時的に適用できますが、ゲノムは突然変異機能に関連付けられていないソフトウェアの他の多くのシナリオで使用される可能性があります。ここでは、他の消費者と、それらにも変異が必要かどうかについて言及しています。

突然変異に関連する状態がある場合、2つの異なるライフタイムが融合していることは二重に真実であると思われます。インスタンスフィールド間でライフタイムが異なる場合は常に、これは複数の概念をばらばらにすることを示しています。


物事に名前を付けるのは難しいです。アプローチ1では、変異には別の名前の方が適している可能性があることをお勧めします。それは突然変異そのものではなく、突然変異の種類、アプローチ、原因、または戦略です。変異という用語は、口語的に結果を変異の原因(ゲノムに)に適用したことを指します。

5
Erik Eidt

方法2は、動作がデータのある場所に存在するという最も基本的なオブジェクト指向の原則に基づいたデフォルトの設計です。また、最も保守しやすく、最も簡単なものです。

だから、私は方法1が絶対に必要になるまでそれを続けます。後でリファクタリングすることができます。したがって、最も単純な設計から始めて、すぐにメリットが得られる場合にのみ、間接指定/分離を導入してください。

1