🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Q&A

解決済

5回答

8550閲覧

継承した場合のstatic変数/関数について

nono1234

総合スコア25

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

0グッド

1クリップ

投稿2021/02/01 14:26

編集2021/02/02 15:10

継承した場合のstatic変数/関数の扱いについて悩んでいます

C#

1//Program.cs 2using System; 3using System.Collections.Generic; 4using System.Linq; 5 6namespace ConsoleApp1 7{ 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var BoyDict = new Dictionary<string, int>() { { "Taro", 12 }, { "Jiro", 13 }, { "Sabu", 14 } }; 13 var GirlDict = new Dictionary<string, int>() { { "Ichi", 15 }, { "Ni", 16 }, { "San", 17 } }; 14 15 // DictionaryからBoyインスタンスを作成 16 var BoyList = BoyDict.Select(_boy => new Boy(_boy.Key, _boy.Value)).ToList(); 17 Console.WriteLine(String.Join(",", Boy.NameList)); // Taro,Jiro,Sabuが出るし、それで正しい 18 Console.WriteLine(String.Join(",", Girl.NameList)); // この時点はListが空であってほしいがTaro,Jiro,Sabuが出る 19 20 // DictionaryからGirlインスタンスを作成 21 var GirlList = GirlDict.Select(_girl => new Girl(_girl.Key, _girl.Value)).ToList(); 22 Console.WriteLine(String.Join(",", Boy.NameList)); // Taro,Jiro,Sabuが出てほしいがTaro,Jiro,Sabu,Ichi,Ni,Sanが出る 23 Console.WriteLine(String.Join(",", Girl.NameList)); // Ichi,Ni,Sanが出てほしいが、Taro,Jiro,Sabu,Ichi,Ni,Sanが出る 24 25 } 26 } 27}

C#

1// Person.cs 2using System; 3using System.Collections.Generic; 4using System.Text; 5 6namespace ConsoleApp1 7{ 8 abstract public class Person 9 { 10 string Name; 11 int Age; 12 public static List<string> NameList = new List<string>(); 13 14 public Person(string Name, int Age) 15 { 16 this.Name = Name; 17 this.Age = Age; 18 NameList.Add(Name); 19 } 20 21 public static void SaveNameList(){ 22 // NameListをcsvにする処理。これはBoy,Girlで共通 23 } 24 25 } 26 27 public class Boy : Person 28 { 29 30 public Boy(string Name, int Age) : base(Name, Age) 31 { 32 33 } 34 35 } 36 37 public class Girl : Person 38 { 39 40 public Girl(string Name, int Age) : base(Name, Age) 41 { 42 43 } 44 45 } 46 47 48}

このようにPersonクラスを継承したBoyクラスとGirlクラスがあります.
Personクラスはインスタンス生成時に自身の場のNameListに生成された人の名前のリストを自動的に保存します.

こんな感じで,BoyとGirlでそれぞれNameListを持たせたいのですが,実際にこのコードを実行すると,2つ問題があります.
1:Person Boy GirlのNameListが同一のものになっているので別々に持たせたいです.
Boy Girl側でPublic new static List<string> NameListをしたら持たせられるのですが,Person側でできないでしょうか?
2:staticメソッドのSaveNameListもPersonクラスのNameListを参照するため,想定の動作をしません.
どのようにすればよいでしょうか?

また,そもそも設計思想が間違っているのでしょうか?
(NameListをPersonのstaticにすべきでないなど)

2021/2/2追記:

みなさまから多くの意見を頂き本当にありがとうございます.
まず最初に謝らせていただくこととして,このコード例は問題を具体化したかったために,作った
ものです.
やりたかったことはabstract classを継承した子クラスが,それぞれstaticな変数を持つ時に親クラスでstatic宣言した場合,親クラスのものと同一のものになるのではなく,子クラスでstaticなものを持っていてほしいということです.(Personの場,Boyの場,Girlの場があり,それぞれに同様の意味を持つstaticな変数を持たせたい)
そして,staticな関数の中で,自身の場を参照したいような時にも親クラスの場を参照してしまうという問題点を解決したいというものです.
適当な例としてstaticなNameListと,staticなNameListをCSV出力する関数を挙げたつもりでしたが不適切でした.確かにPersonがNameListを持つべきではありません

例えば染色体(Chromosomes)をPersonは持っています.これはどのPersonにもあり,インスタンスごとに違うものでもないのでstaticです(もしかしてここの理解が間違っているのでしょうか?).ただし,Personの染色体はこの時点では不定なので,定義だけされています.
Personを継承したBoyも染色体を持ちます.Boyの場合はxyです.Girlの場合xxです.

この時Boy.Chromosomos="xy", Girl.Chromosomos="xx"だと思うので,親と,それを継承した子1, 子2......で別のstaticな変数が欲しいという場面はあると思います

またややこしい例を持ち出して申し訳ありませんが,私がNameListを例として挙げてしまったがために本筋と外れた議論になってしまったので追記させていただきます.

//追記その2
staticにすべき変数論に発散してしまったので,一度締めさせていただきます。
みなさまのご意見非常に勉強になりました.
頂いた意見の中では

  • 抽象プロパティで定義する(もしかすると実際にはできない?)
  • PersonMangerクラスで管理する

が特に参考になりました。

今回の例では具体的過ぎて,「Personであったらそのように実装すべきでない」という意見を数多く頂きましたが,実際クラスで一括管理したいstaticなものがあると思うのですが,どうやらstaticの認識がみなさまのものと違っているようです.もういちど勉強します・

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/02/01 14:35

> また,そもそも設計思想が間違っているのでしょうか? > (NameListをPersonのstaticにすべきでないなど) 設計思想が間違っていると思いますし、まずはstaticにしなければ良いのでは?なぜ、staticにしようと考えましたか? staticは、インスタンスに関わらずクラスの全てで共通になります。
dodox86

2021/02/01 14:38

「Person」と、クラス名から想定するカバー範囲はひとりの人物を指すようなイメージに対して、NameListと複数人を想定するフィールドを持つことも、設計思想が間違っている感があります。
nono1234

2021/02/01 14:48

>「Person」と、クラス名から想定するカバー範囲はひとりの人物を指すようなイメージに対して、>NameListと複数人を想定するフィールドを持つことも、設計思想が間違っている感があります。 この部分は自分でもなんとなくそうではないかと思います. 呼び出し側で管理すべき案件だというのは理解しています. メタクラス的なものが欲しいのですが...
Zuishin

2021/02/01 15:02 編集

そもそも辞書を使って名前をキーにするところから無茶苦茶。設計思想は合っている間違っているのレベルではなく、思想が無いようにしか見えません。NameList など何の役に立つのかわからないリストを static で保持する理由はないし、百歩譲ってどうしても必要な場面が仮にあったとしても var boyNameList = BoyList.Select(a => a.Name).ToList() で十分です。BoyList から Name にアクセスすればいいだけなので、boyNameList が必要な場面がまったく想像つきませんが。
Zuishin

2021/02/01 15:13

それでもどうしても質問のようなことがしたいなら、Person に実装するのではなく Boy と Girl にそれぞれ実装すればできます。多態性を使いたいならインターフェースを作りましょう。
退会済みユーザー

退会済みユーザー

2021/02/01 15:33 編集

そもそも性別毎にクラス作る必要も無いと思うんですが、Personに性別のプロパティ追加すればいいんじゃないですかね。 名簿のようなものをイメージする時、一人分のデータを表現するのにどういう項目が必要になるか考えてみるといいと思います。そこにNameListが必要でしょうか?あったら変ですよね。
nono1234

2021/02/01 15:39

辞書からインスタンス生成したのは,例としてさらっと書きたかったのですみません 確かにNameListが頻繁に呼ばれないのであれば,BoyList.Select(a => a.Name).ToList() で十分です. ありがとうございます. インターフェース作っても,結局BoyとGirlでSaveNameListを記述しなければならないのではないのでしょうか(インターフェースのデフォルト処理で行けるのでしょうか?)
nono1234

2021/02/01 15:46

@radianさん ここに書かれている部分だけで言えば確かにそうなのですが,例えばBoyだけに特定の関数持たせたかったりBoyとGirlで関数の名前同じだけど別のことをさせたいというようなこともあるので,BoyとGirlは分けたいです. NameListをPersonに持たせるべきではないというご指摘に関してはおっしゃる通りだとおもいます.
退会済みユーザー

退会済みユーザー

2021/02/01 15:52 編集

> 例えばBoyだけに特定の関数持たせたかったりBoyとGirlで関数の名前同じだけど別のことをさせたいというようなこともあるので そういう事なら、クラス作らざるを得ないかもしれませんね。抽象メソッドを使用すると良いかもしれません。
nono1234

2021/02/01 15:56 編集

ここに関しては,性別をPersonにいれたら良いというご指摘に対しての反論のつもりでした ご配慮ありがとうございます
退会済みユーザー

退会済みユーザー

2021/02/01 15:56

提示されてるコードだけからは、さすがに実装するつもりのことはエスパーじゃないので読み取れません。
Zuishin

2021/02/02 11:19

追記を見ましたが、このような場合、Boy のコンストラクタで xy に設定し、Girl のコンストラクタで xx に設定します。 まず static を使う状況を無理やり考え出そうとしているところが間違っています。コードは問題を解決するものであり、思いつきの使いたいコードを無理やり使うものではありません。問題がないのならば色物は放置してその前にすることがあると思います。
nono1234

2021/02/02 12:00

追記に関してはこのページでの議論が私のNameListの例により異なった方向に進んでいたために提示したもので,この質問を投稿した時から質問の本質は変わっていません 「staticな場を持つ」クラスを継承したいが,そのstaticな場は別で持ちたいというものです.インターフェースに近いかと思いますが,その場に対して行いたい行為は一律なのでインターフェースほど抽象的でなくてもよいという感じです
Zuishin

2021/02/02 12:23

ただなんとなく「持ちたい」というのがそもそもの間違いで、プログラミングとはかけ離れているという意味です。
退会済みユーザー

退会済みユーザー

2021/02/02 12:27 編集

結局のところ、何をもって解決とするかがさっぱり見えないのですが。後付けて色々条件足されるとキリがないです。最初の質問の答えはきちんと返している回答がついてるので、一度ベストアンサー付けて締めて設計し直したらどうです?それで作り込んでいって、問題が出てきたら改めて質問すればよいでしょう。
nono1234

2021/02/02 14:52

@Zuishinさん 持ちたいというのは,それを親の方で一括管理した記述をすることが出来れば,子の方で定義する必要がないからです(同じことを二度書くべきではないというのはプログラミングの原則かと思います)
nono1234

2021/02/02 14:55

@radianさん 確かに発散してしまっているところがあるので,いちど締めたいと思います
Zuishin

2021/02/02 15:58 編集

子の方で定義する必要など最初からないので親でも定義しなくて大丈夫です。一度も定義する必要のないものを一度定義しようとするのはプログラミングの原則ではありません。
actorbug

2021/02/02 21:01

「あるオブジェクトが特定のインスタンス変数を持つべき」だと指定したいのであれば、 クラスでそのように指定するのが普通です。 同様に、「あるクラスが特定のstatic変数を持つべき」だと指定したいのであれば、 クラスのクラスであるメタクラスで指定するのが普通でしょう。 それをクラスの継承で実現しようとしているのが、そもそもの誤りではないでしょうか。 そういうことをやりたいのであれば、メタクラスの存在する別言語に移行することをお勧めします。
guest

回答5

0

ベストアンサー

そもそも論

ソースコードは目的に沿って書くものです。
ソースコードはその目的が分かりやすく、かつ読みやすいように表現されるべきです。

オブジェクト指向では、目的に沿ってオブジェクトを定義します。
また、クラスであったりメンバーであったりは名が体を表すべきです。

例え、C#のどんな設計思想であれ、これ等の基本的な思想からはブレてはいけません。
これがそもそも論でお伝えしたいポイントです。

この基本的な思想からブレていないかもう1度ソースコードを見直してください。

問題点1

PersonはNameListを持っているので、Personという名前はふさわしくないかと思います。
「人は自分の名前と年齢と全人類の名前を知っている」という文章を見て違和感を覚えるのと同じです。

なので、下記のような対策をいずれかしてください。

  • Personという名前を別のふさわしい名前に変える
  • 別のふさわしい名前がなければNameListを持つべき別のクラスを定義する
  • そもそもNameListを持たないようにする

少なくとも、Personという名前のクラスがNameListというメンバーを持ってはいけません。

問題点2

今回の質問では、staticを使いたいように読めます。
staticも目的に沿って使うものです。

インスタンスに属するデータに依存しない、副作用のない処理を定義したいという目的がnono1234
さんにあればstaticでも構いません。

Person Boy GirlのNameListが同一のものになっているので別々に持たせたいです.

上記修正をした場合、NameListはstaticを外す必要があります。
すなわち、インスタンスに属するメンバーとして定義することになります。

すると、SaveNameListメソッドはインスタンスに属するデータに依存することになるため、非staticでなければいけません。

もしかすると

今回の目的は人の名前・年齢を性別単位で取得することでしょうか。
NameListはPersonよりも外の世界で作れば良いのではないでしょうか。

C#

1var people = new List<Person>(){ 2 new Boy("Taro", 12), 3 new Boy("Jiro", 13), 4 new Boy("Sabu", 14), 5 new Girl("Ichi", 15), 6 new Girl("Ni", 16), 7 new Girl("San", 17), 8}; 9 10var boys = people.Where(x => x is Boy); 11var boyNames = boys.Select(x => x.Name); 12Console.WriteLine(String.Join(",", boyNames)); // Taro,Jiro,Sabu 13 14var girls = people.Where(x => x is Girl); 15var girlNames = girls.Select(x => x.Name); 16Console.WriteLine(String.Join(",", girlNames)); // Ichi,Ni,San

C#

1// Person.cs 2using System; 3using System.Collections.Generic; 4using System.Text; 5 6namespace ConsoleApp1 7{ 8 public abstract class Person 9 { 10 public string Name { get; set; } 11 public int Age { get; set; } 12 13 public Person(string Name, int Age) 14 { 15 this.Name = Name; 16 this.Age = Age; 17 } 18 } 19 20 public class Boy : Person 21 { 22 public Boy(string Name, int Age) : base(Name, Age) 23 { 24 } 25 } 26 27 public class Girl : Person 28 { 29 public Girl(string Name, int Age) : base(Name, Age) 30 { 31 } 32 } 33}

大事なのは、目的がないソースコードを書かないことです。
ソースコードは目的に沿って書くものだからです。

追記について

例えば染色体(Chromosomes)をPersonは持っています.これはどのPersonにもあり,インスタンスごとに違うものでもないのでstaticです

PersonはBoyかもしれないしGirlかもしれません。すなわち、Personが持つ染色体はxyかもしれないしxxかもしれません。すなわち、PersonのChromosomesはstaticではありません。

例えば染色体みたいなBoy全体が持っていて,かつxyと決まっているものでしたらstatic変数かと思うのですが,いかがでしょうか?

こちらの質問もまず前提にはなりますが、staticはそもそもオブジェクト指向の考えにはないキーワードです。ポリモーフィズム(今回でいう継承)とstaticは相性が悪いので混ぜられません。

私なら下記のように抽象プロパティを使って実現します。

C#

1public abstract class Person 2{ 3 public string Name { get; set; } 4 public int Age { get; set; } 5 public abstract string Chromosomes { get; } 6 7 public Person (string Name, int Age) { 8 this.Name = Name; 9 this.Age = Age; 10 } 11} 12 13public class Boy : Person 14{ 15 public override string Chromosomes { get; } = "xy"; 16 public Boy (string Name, int Age) : base (Name, Age) { } 17} 18 19public class Girl : Person 20{ 21 public override string Chromosomes { get; } = "xx"; 22 public Girl (string Name, int Age) : base (Name, Age) { } 23}

BoyとGirlにstaticなメンバーを持たせて実現もできますが、それならオブジェクトを作るのではなくenumを作ってそこから"xy"だったり"xx"の情報を得る方がわかりやすくて良いと思います。

C#

1public enum HumanChromosomes 2{ 3 Male = "xy", 4 Female = "xx" 5}

投稿2021/02/02 07:48

編集2021/02/02 12:17
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nono1234

2021/02/02 10:55

問題点1に関しては,まさにその通りだと思います.本文の方に追記したのですが,例えば染色体みたいなBoy全体が持っていて,かつxyと決まっているものでしたらstatic変数かと思うのですが,いかがでしょうか?
BluOxy

2021/02/02 12:18

回答に追記しました。
BluOxy

2021/04/05 05:59 編集

staticなフィールド・プロパティを持たざるを得ないケースはほとんど無いと思います。 例えば、アプリケーションの開発で各クラスにstaticなフィールド・プロパティが平均2個ぐらい定義されているとします。 定義したそれ等が読込&書込可能である場合、それ等の状態は現在どうなっているのかまったくイメージができません。保守が困難です。すぐにリファクタリングしたいです。 読込限定である場合、定数の記述箇所がバラバラでコードを追うのが面倒臭いです。読む気が無くなります。enumか何かで記述箇所がまとめられないか検討します。 staticなメソッドは、Mathクラスが持つメソッドのような用途であれば作ってもありだと思います。 逆にそれ以外はなしです。
nono1234

2021/02/02 15:00

>PersonはBoyかもしれないしGirlかもしれません。すなわち、Personが持つ染色体はxyかもしれないしxxかもしれません。すなわち、PersonのChromosomesはstaticではありません。 >staticはそもそもオブジェクト指向の考えにはないキーワードです。ポリモーフィズム(今回でいう継承)とstaticは相性が悪いので混ぜられません やはりChromosomesはstaticであるべき変数で,C#の言語仕様上staticが共有されてしまうというのが本質な気がします.
BluOxy

2021/02/25 00:47 編集

私は今回のケースにおいて static を利用することが分かりやすい・本質的であるとは思いません。 どの文章を読んで「やはり」と考えていらっしゃるのかは分かりませんが、static を利用することが分かりやすいかつシンプルと感じるのであれば、それでも良いと思います。個人で管理するコードに対して当人がそう思うのであればその思想は尊重いたします。 ただし、チームで管理しているのであればチーム内で思想を統一すべきと思います。
BluOxy

2021/02/03 10:15 編集

もう1つかいておくと、C#のようなオブジェクト指向言語ではSOLID原則に従うことで読みやすく保守しやすいソースコードが書けます。 staticはその原則を阻害する要素なので基本的には使うべきではありません。
guest

0

##追記に対する回答

例えば染色体(Chromosomes)をPersonは持っています.(以下略)

例えが不適切です。
なるべく質問内容の例えに寄り添って考えたとしても、

染色体を持つのは実態としての人間(インスタンス)であり、概念としての人間(クラス)ではありません

という回答になります。

コメントや他の回答等でも指摘されてると思いますが(あんまり読んでないけど)、そもそもstaticを使うことを目的化しないでください。

staticは利用する必要がなければ避けるべきものです。
あなたがstaticが必要な例が思いつかない(つまり必要としていない)のなら、必要になってから考えてください。


また,そもそも設計思想が間違っているのでしょうか?

(NameListをPersonのstaticにすべきでないなど)

はい。
で終わっちゃう。

staticはPersonクラスに属しており、子クラスから参照されても別々の実態になるわけじゃないので。

なので

どのようにすればよいでしょうか?

色々やりようはあるだろうけど、最低限staticやめたらいいんじゃないですか。

投稿2021/02/01 14:30

編集2021/02/02 12:34
gentaro

総合スコア8947

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nono1234

2021/02/01 14:56

staticをインスタンス変数にしてしまうと,各インスタンスがそれぞれNameListをもつというような変な状況になりませんか?(そもそもPersonがNameListを持つというのが変なのかもしれないですが)
gentaro

2021/02/02 03:26

そもそもそのNameListというのがそのクラスに属しているのが間違いってこと。
nono1234

2021/02/02 11:03

確かにNameListがPersonにあるのはおかしいです.追記した部分にも書いたのですが,例えば染色体みたいなものでしたらどうでしょう?
nono1234

2021/02/02 15:01 編集

staticをできるだけ使わないほうがよいというのは,なにかまちがっていませんか?staticにすべき.そうでないは,その変数が何を表すかによるものだからです
gentaro

2021/02/02 15:11

そもそもstaticというのは昔の言語で忌み嫌われていたglobal変数・関数なんかと同じ性質を持っており、オブジェクト指向と相容れない性質が多分にある。 それを理解した上で、実装上の都合で利用するケースはあるけど「staticありき」の設計はオブジェクト指向型言語を使う上では基本的に避けるべき、という事。 「staticおじさん」とかでググると色々教訓が得られると思うけど。
gentaro

2021/02/02 15:30

まぁこれは書くかどうか迷うところだけど > staticをできるだけ使わないほうがよいというのは,なにかまちがっていませんか?staticにすべき.そうでないは,その変数が何を表すかによるものだからです 間違ってない。staticを利用しても問題ないと判断できるレベルに達していない人がstaticを多用しがちだし、そういう人がチームにいると質の悪いコードを量産するんで周りが迷惑。別に責めたいわけじゃないけど、質問文で挙げられた例を見てもあなたがそのレベルに達してるとも思わないんで、使わない方が良い。 てか判断基準は「変数が何を表すか」じゃない。 その変数なりメソッドなりが「どのように利用されるか」の方。 使い方から判断して(主に利便性の観点で)staticであっても(インスタンスを毎度生成しなくても)問題ない、という判断ができないのにstaticをやたら使おうとする姿勢が問題。 C#であれば標準ライブラリ等に含まれる質の高いコードでstaticがどう使われてるのか見て考えたほうが良い。あなたが質問文に提示したようなケースと同じような使い方は絶対してないんで。
guest

0

staticというのは、インスタンス別に持たれるんではなく、クラスで持たれるもんです
なので、継承しようとも一つしか存在しません

投稿2021/02/01 14:33

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nono1234

2021/02/01 15:01

クラスで持たれるのは理解しているのですが,BoyにはBoyの場,GirlにはGirlの場があるはずで,そういうものを作成するときにParentを継承させて作るという方法が間違っているのでしょうか? また,Personには自身のNameListをCSV化するといったようなBoyにもGirlにも共通のstaticなメソッドがありますが,これも一つ一つBoyGirlに記載するのは煩雑です. なにか良い方法はないでしょうか?
y_waiwai

2021/02/01 15:06

あくまでPersonで持たれてるもんで、継承しても同じものを指します。 static関数といえどもそれは同じです なにか大きな勘違いしてるようですが。 static外せばいいだけだと思うけど、それではだめなの?
nono1234

2021/02/01 15:14

static外すと,SaveNameListで所望の動作ができなくなるのではと思います. SaveNameListは今まで作成したインスタンスの名前をcsvに保存するような関数です
y_waiwai

2021/02/01 15:15

まず外してみて、動作を確認してみたら?
guest

0

  • SaveNameList()は,Boy,Girlで共通の実装を使いたい
  • SaveNameList()はstatic
  • staticなリスト(List<string>)を保有する必要がある
  • BoyとGirlで別々のリスト

以上より,

CSharp

1public class NameList 2{ 3 private List<string> TheList = new List<string>(); 4 5 public void Add( string Name ){ TheList.Add(Name); } 6 public void SaveNameList(){ /*リストTheListの内容をcsvにどうの*/ } 7} 8 9public class Boy 10{ 11 public Boy(string Name, int Age){ TheNameList.Add( Name ); } 12 13 //static 14 public static void SaveNameList(){ TheNameList.SaveNameList(); } 15 private static NameList TheNameList = new NameList(); 16} 17 18public class Girl{ /* Boyと同じ */ }

投稿2021/02/02 08:03

編集2021/02/02 08:08
fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nono1234

2021/02/02 10:52 編集

Person側にNameList関連の機能を持たせるべきではないというのはおっしゃる通りだと思います.これも実装の一つとして参考にさせていただきます。
fana

2021/02/03 01:30

「何をどこに持たせるべきか」とか「本当に持つべきか」とか「staticたるべきなのか」とかいう,そもそも論的な話を一切含まず,単に 「Personのstaticとしてデータがあってそれを継承」という方法だと「BoyとGirlで別々のリスト」が達成できない のであれば,じゃあ他の形にするしかないよね,というだけの内容です. これが何らかの意味で良い形だとかいうことでもなくて,列挙された条件を満たす形の1つを挙げただけ,的な.
guest

0

ご理解を深めていただくため、
一旦、結論を控えます。

>1:Person Boy GirlのNameListに追加されてしまいます.
staticとすることで、どうなるか、
プログラムとしての影響をご理解されていますか?
※ご自身なりの考えでも構いませんので、
返答いただければと思います。

その部分の理解不足によるものです。

投稿2021/02/01 14:33

WhiteTempest

総合スコア404

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nono1234

2021/02/01 14:49 編集

ご回答ありがとうございます. なぜこうなるかは理解しています. ただstaticな場に生成されたインスタンスの情報を保存するようなクラスが大量に必要な時に,元となるクラスを継承するのが一般的かと思うのですがstaticまで継承しないような方法はないかということです
WhiteTempest

2021/02/01 14:43

staticというのは、クラス変数というものになります。 クラス変数とは、システム内で一意になる変数です。 staticを付けない場合、インスタンス変数というものになります。 これは、new毎に個別の変数となります。 今回の目的であれば、new毎に別々の領域になって欲しいのであれば、 インスタンス変数(staticなし)にするのが正しいです。 もしかしてですが、BoyとGirlそれぞれに クラス変数として用意したかったから 親にstatic宣言したということでしょうか?
nono1234

2021/02/01 14:52

そのとおりです. Personはstaticメソッドとして自身のNameListをCSVにするみたいなメソッドを持っています これはBoyでもGirlでも同一の操作なので一々BoyとGirlクラスに記載するのは煩雑です そのため,staticなNameListを持ったクラスが必要なのですが......
WhiteTempest

2021/02/01 15:03

親で共通処理にさせたいから、 親にstaticしたいんですね。 ただ、今回の目的ですと、BoyとGirlで 別々の実体を持つ必要があるので、 現在の思想では実現不可だと思います。 代替案としては、かなり幅広くありますが、 とりあえず2つ例示します。 ①public static abstract List<string> NameList;にする。  子クラスで実体を持って貰うため、  抽象プロパティとして、子に宣言を義務付ける。  出来たような記憶はありますが、  保証できかねます。。。 ②管理クラスを設ける  Boys, Girlsなどの管理クラスを設け  リスト管理することとし、  Boy, Girlのコンストラクタで、  thisをaddする
WhiteTempest

2021/02/01 15:08

個人的には、後者ですね。 Personという、個人を司る名前のクラスに全員の名前を持たせるのは、 思想的に受け入れれないです。。。 実際の現場でも、●●Mngや、●●sといった、管理、複数形を司るクラスを作る方が 一般的だと思います。 ※●●Mngや●●sのクラスに単数形のリストを持つ方が、扱いやすいかと。
nono1234

2021/02/01 15:21

マネージャークラスを作ってその中で管理するというのは腑に落ちました. やはりPersonはPersonであり,NameListのような他のインスタンスの情報を持つべきではありません. PersonManagerクラスの中にPersonListとgetPersonNameListとSaveNameList作るのが良い気がしてきました ありがとうございます
WhiteTempest

2021/02/01 15:32

極論ですが、現実世界で考えた時に 一人が全世界の人の名前を知っているか? と考えると暴挙具合が顕著だと思います。 会社なり組織なりの上位が居て、 その中に属している一人、という管理の方が 真っ当ですしね。 オブジェクト指向開発をやるにあたっては、 コードという性質上、 如何様にも実装できるという実態もありますが、 管理や可読性を考慮した、読みやすくメンテしやすい設計のため、 日々勉強です。 少し古い考えかもしれませんが、 モデル駆動開発、抽象化の演習、オブジェクト指向モデリング、デザインパターン、などなど、 多分終わりなき勉強の日々が待ってます(笑)
退会済みユーザー

退会済みユーザー

2021/02/01 15:44

> ①public static abstract List<string> NameList;にする。 >  子クラスで実体を持って貰うため、 >  抽象プロパティとして、子に宣言を義務付ける。 この書き方だとフィールドだし、静的プロパティだとしてもabstractには出来ません。
WhiteTempest

2021/02/01 23:38

raddianさん ご返答ありがとうございます。 見返してみるとおかしな回答でしたね。。。 ※そもそも、そんな実装のやり方をやらないからうろ覚えでした。。。 static abstractって出来ないんですね。 ご指摘受けて調べ直せて、勉強になりました。 【参考にしたURL】 https://www.atmarkit.co.jp/ait/spv/1801/10/news017.html#abstract
BluOxy

2021/02/02 09:00 編集

> PersonManagerクラスの中にPersonListとgetPersonNameListとSaveNameList作るのが良い気がしてきました PersonManagerは何をするクラスなんでしょうか。 CSV出力が目的であれば、PersonManagerをわざわざ定義しなくてもStreamWriterやサードパーティ製ライブラリのCsvHelper辺りを使えば達成できます。 人の一覧を取得して何かに使うことが目的であればPersonManagerをわざわざ定義しなくてもその目的に沿った手段を取るべきです。 目的が明確でないクラスを新たに作ればプログラムは意味もなく複雑になります。 https://qiita.com/magicant/items/8134edf969f9629fa66e#downloadmanager-animationcontroller-jobprocessor-etc
nono1234

2021/02/02 11:02 編集

クラス内のstaticな処理の一例としてCSV出力を挙げたつもりでしたが,混乱させて申し訳ありません しかし,Personを上から操作するような処理を記述するなら一つ上のクラスで管理するというのは大変しっくりきています. 貼っていただいたURL大変参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問