質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

87.96%

クラス設計の考え方についてヒントをいただけますでしょうか?

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 7
  • VIEW 14K+

score 19

長い文章で申し訳ありませんが、
設計(クラス分担の考え方)について教えていただければ幸いです。

ファイルA
ファイルB
ファイルC

を読み込み、それぞれに対して、

処理1
処理2
処理3

をした結果をクロス集計のように出力したいと思っています。

具体的な出力結果としては、

・ファイルAに対して処理1,2,3を行った結果を一覧出力。
 (ファイルB,ファイルCも同じく)

・処理1をファイルA,B,Cへ行った結果を比較一覧出力。
 (処理2,処理3も同じく)

と両方向から集計する感じです。

このとき、

・データの読み書きを担当するクラス

・データに処理を加えるクラス

・結果を出力するクラス

を作って進めようと思ったのですが、考え方は合っていますでしょうか?

悩んでいるのは、
「データの読み書きするクラス」でデータを配列に準備した場合、
その配列を「データに処理を加えるクラス」で使うには
引数で渡すことになると思うのですが、それが正しいのかどうかです。

特に、渡すべきデータ(配列)が多岐に渡っている場合は
引数で渡すのが正しいのか・・・
(引数は1~2つが妥当という意見とはかけ離れるので・・・)

もちろんクラスごと引数で渡してしまえば記述上は1つで良いのかもしれませんが、
こういう思考になること自体がクラスの役割分担などで
何か間違っているような気がして質問させていただきました。

オブジェクト指向(?)に慣れていない思考だと、
どのクラスからもアクセスできるグローバルなデータ用の配列を準備しておいて、
それぞれのクラスからアクセスすれば簡単なようにも思えます。
ただ、その方法だと仕様を拡張する時、
グローバルな配列をどんどん増やさなければいけない気もするので、
それはそれで何か違うような気がしています。

以前プログラムしていた言語が関数のスコープが緩く、
(下位の)呼ばれた関数が(上位の)呼んだ関数の変数はそのまま使えていたので、
どうして良いか分かっていないのもあります。

抽象的な質問で申し訳ありませんが、
アドバイスいただければ幸いです。
ご不明な点がありましたら補足しますので、
遠慮無くご指摘いただければ幸いです。

よろしくお願い致します。

※最後にプログラム的な表記も併記させてください。

Class データ読み書き
{
    public string d_data = new string [1000];  //データ用配列 (実際は十数個)

  public void データ読み込み (string ファイル名)
  {
        StreamReader sr = new StreamReader(ファイル名);

        while (sr.Peek() > -1)
        {
            d_data[i] = sr.Readline();  // データ用配列にファイル内容を読み込む
            i++;
        }
    }
}


Class データ処理
{
     public void 処理1 (データ元)
     {
          処理1;
          return;
     }

     public void 処理2 (データ元)
     {
          処理2;
          return;
     }

     public void 処理3 (データ元)
     {
          処理3;
          return;
     }
}

void main
{

    データ読み書き d1 = new データ読み書き;

    d1.データ読み込み(ファイルA);  // データ用配列に読み込む

    データ処理 d2 = new データ処理;

    d2.処理1(d1);  // ←ここでd1の配列データを渡すために、
    d2.処理2(d1);  //  d1(クラス)を引数で渡すことになる設計は正しいのか?
    d2.処理3(d1);  //  データ処理のクラス内では、d1.d_data とアクセスしています。

    ...

}

ベストアンサーを付ける形のようなので、
tkow様に付けさせていただきましたが、
どの方の回答も非常に参考になります。

概略を書かせていただきますと、

unau様は 大きな枠組みでのクラス設計や実装
tkow様は クラス設計に加え、コンテキスト処理を含めたスマートな記述法
tkturbo様は クラスのインスタンスにおける static の利用やメモリの節約法

などが勉強できますので、後からこの質問を参照する方は、
概要を参考に回答を見ていただけると良いかもしれません。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

class設計の一つの基準はそのインスタンスを複数生成する必要があるかないかです。
一つ定義されていればデータの内容を変える必要がないものはクラスにする必要性はほとんどありません。
例外としては,staticメソッドのみをグループ化するライブラリなどを作る場合,static Classで実装することがあります。このとき,インスタンスを作成したり,定数以外の内部変数を処理するような実装にしてはいけません。なので,定数は,readonly属性を作るようになると思います。

質問者様がデータ処理のクラスを他のコードで使い回す可能性があるのなら,処理のクラス化はokです。
C#では,Listを使えるので,いくらデータが入るかわからないものは配列ではなくListにしましょう。
arrayとListは相互に変換できるので,Listの方が無難です。

また,コレクションの要素一つ一つにやる処理に対して,引数を配列にするのはやめましょう。なぜなら,Listやarrayには,関数を引数に取ると,要素の一つ一つにその関数を適用して要素を返す関数が存在したり,処理を並列かするのが簡単に出来るからです。

個人的にはこういう流れで書きます。実行環境なしで書いているので,文法のミスなどがあったら調べて直してください。また最適とまではいかない可能性があるので参考までにしてください。namespaceなどは省略しています。

Class データ読み書き
{
  public List<string> d_data {get;,set;};  //データ用list
  public データ読み書き(string[] input){
      d_data = new List<string>();
      foreach(var file_name in input){
       データ読み込み(file_name)
      }
  }
  public void データ読み込み (string ファイル名)
  {
        (using StreamReader sr = new StreamReader(ファイル名)){
     string temp="";
//仕様だとファイルごとの処理と書いてあったのでファイルごとにしました。行ごとにしたければ二次元Listになおしてください。
        while (!sr.EndOfStream)
        {
            temp += sr.Readline();  // データ用配列にファイル内容を読み込
        }
        this.d_data.push(temp);
      };
    }
}


Class データ処理
{
     public void 処理1 (データ元)
     {
          処理1;
          return データ元;
     }

     public void 処理2 (データ元)
     {
          処理2;
          return データ元;
     }

     public void 処理3 (データ元)
     {
          処理3;
          return データ元;
     }
}

 static void main(string args[])//argsでファイル名指定
{
  using static データ処理;
    データ読み書き d1 = new データ読み書き(args);

    var data_list = d1.d_data.Select(element=>{
    //書き直しました
    element=処理1(element);  
    element=処理2(element);  
    return 処理3(element);     
    }).ToList();


    ...

}

また,処理の対象がデータが一種類しかしないのであれば処理クラスの処理をデータ読み書きのクラスに移してデータクラスとしたほうがオブジェクト指向っぽくなります。個別のデータが自分自身のデータを直接操作できるほうがいい場合オブジェクト指向に向いた設計になります。

Class データ
{
  public string d_data {get;,set;};  //データ用list
  public データ(string input_file){
      d_data ="";
      (using StreamReader sr = new StreamReader(ファイル名)){
     string temp="";
//仕様だとファイルごとの処理と書いてあったのでファイルごとにしました。行ごとにしたければListになおしてください。
        while (!sr.EndOfStream)
        {
            d_data += sr.Readline();  // データ用配列にファイル内容を読み込
        }
      処理1();
      処理2();
      処理3();

      };
  }


    public void 処理1 ()
     {
         d_dataの処理
     }

     public void 処理2 ()
     {
          d_dataの処理
     }

     public void 処理3 (データ元)
     {
          d_dataの処理
     }
}


 static void main(string args[])//argsでファイル名指定
{
   List<データ> data_list=args.Select(element=>new データ(element)).ToList();
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/17 20:12

    ご返信遅れて申し訳ないです。

    C#3.0で書かれているのですね。現在C#6.0までリリースされているので開発環境的に無理でなければC#6.0で開発されることをお勧めします。
    .netframworkも4.5以上とそれよりも下のバージョンでは機能の充実性がかなり違うので,できれば上の方のversionを使う方が簡単に早くスッキリ書けてお勧めできます。

    >一応、クラスにした経緯ですが、
    データを保存する配列をファイル毎に用意したいので、
    保存用の配列と読み書きのメソッドがクラスでパッケージになっていたら
    頭で整理するのが楽かなと思って作りました。

    オブジェクトというデータ構造にすることで実態が捉えやすいものになる場合は,一つ以上インスタンス生成しないようなものでもクラスにするのはありです。例えば,リモコンという機械は一つ以上必要ありませんが,リモコンというクラスの概念を作ると,リモコンの機能が想像しやすいというのであれば,クラスにするのは良い設計です。なのでそのような意図で作られたのであれば使い方としては問題ありません。

    あと,C#はクエリを直書きできますし,LinqはほぼSQL構文をC#のデータ構造に適用するだけでなく,データベースアクセスの時にも使えます。なのでLinqで書くことに慣れていると,SQLを使わなくても,簡単にデータベース操作することができます(C#の最も良い利点の一つだと思います)。MySQLServer使う場合もLinqの構文は生きるので是非覚える都良いと思います。

    また,

    > データを読み込んで配列にするクラスは入れ替えられたら楽かも

    これは,ジェネリックという機能を用いると可能です。また,VisualStudioは独自にO/Rマッパーを持っており,データベースの構造からC#用のクラスを自動生成してくれる機能があります。こちらのクラスに共通の独自のInterfaceの型を継承させることで,

    void データ読み書き(独自のInterfase型 data){};

    など引数にInterfaseの型をとる関数として実行することで,インターフェースを継承しているオブジェクトを全て同じ関数の引数に入れて実行できるようになります。

    >特定の順番が保証されている

    使ったことないので名前がすぐに出てきませんがLinqまたはquery構文はデータベース操作を完全にサポートしているので,decend by,accend byに当たる関数があると思います。また GroupByや,Whereで絞り込みもできます。

    >d_data[30] を処理している時に d_data[29] や d_data[28] を参照する。
    >該当行以外のデータを参照する

    ラムダ式の引数を二個とると,第2引数が現在参照している要素のindexをとることができるので,ラムダ式の処理内でそのindexを基準に,他の要素にアクセスしたり,ラムダ式は関数スコープになるので,絶対にアクセスしたい列要素のindexを定数で指定したりということは可能です。また,調べてみると結構関数があるもので,二次元操作くらいであれば,indexを直指定で操作する関数がC#自体にあるかもしれません。
    とはいえこういう処理は可読性を下げてしまうこもあるので,関数の引数を配列にlistにしてindex操作で処理した方が無難かもしれないです。

    是非頑張ってください。

    キャンセル

  • 2016/04/17 20:21

    またいうまでもないかもしれませんが、フォルダの中のcsvを全部指定するみたいなこともできるのでcsvで試したいときはその方法を調べてみるといいと思います!

    キャンセル

  • 2016/04/20 01:32 編集

    返信が大変遅くなりまして、誠に申し訳ありません。


    > C#3.0で書かれているのですね。
    > 現在C#6.0までリリースされているので
    > 開発環境的に無理でなければC#6.0で開発されることをお勧めします。


    申し訳ありません・・・
    ラムダ式などを調べるとC#3.0からだったので、
    C#3.0という表現をしてしまいました。

    制約さえ無ければ、やはり最新の環境が一番ですよね。


    > オブジェクトというデータ構造にすることで
    > 実態が捉えやすいものになる場合は,
    > 一つ以上インスタンス生成しないようなものでも
    > クラスにするのはありです。

    これを聞いて安心しました。
    自分の設計が不安で質問させていただいたのですが、
    ひとまず全くの間違いでは無かったようで良かったです。



    Linqの件についてもメリットを分かりやすく教えていただき、

    ありがとうございました。

    今まで、ACCESS + VBA だったため、

    SQLもウィザードで作られたものを手打ちで直す、なんて事をしていましたが、

    教えていただいたメリットは非常に魅力的だったので、

    SQLの勉強も含め、Linqの構文をもっと勉強していきたいと思います。



    > こちらのクラスに共通の独自のInterfaceの型を継承させることで,
    >
    > void データ読み書き(独自のInterfase型 data){};
    >
    > など引数にInterfaseの型をとる関数として実行することで,
    > インターフェースを継承しているオブジェクトを
    > 全て同じ関数の引数に入れて実行できるようになります。

    Interfaseの機能を理解していないので、

    想像なのですが、読んだだけでも非常に便利そうなので、

    実現するべくやってみます。

    ここは勉強が全く追いついていないので、

    理解した結果をここにご報告できないのですがご容赦ください。

    ちなみに、今回のInterfaseなどもそうなんですが、

    機能単体がそれぞれ説明されているページを見ても、

    「自分の処理にどう当てはめるか?」って意外と分からないので、

    こういった助言は本当に助かります。



    質問させていただいた問題にも回答いただき、
    ありがとうございました。

    ■Linqを使う際に特定の順番が保証されている件

    ヒントをいただいたaccend by等から調べたところ、
    orderby 句 で実現できそうです。

    勉強途中なので他サイトからの引用で恐縮ですが、

    ```lang-c#
    public ActionResult Orderby()
    {
    var articles = db.Articles
    .OrderBy(a => a.Published)
    .ThenBy(a => a.Title);
    return View(articles);
    }
    ```

    OrderBy      昇順にソート
    OrderByDescending 降順にソート

    ※さらに絞り込む場合(第2キー以降)

    ThenBy      昇順にソート(第2キー以降)
    ThenByDescending 降順にソート(第2キー以降)

    出典元:LINQ:データを並べ替える - orderby句[C#]2014.11.18
    http://www.buildinsider.net/web/bookaspmvc5/050303

    となるようです。



    ■Linqで該当行以外のデータを参照する件

    > ラムダ式の引数を二個とると,
    > 第2引数が現在参照している要素のindexをとることができる

    まさにLinqを使う上で求めていた情報です。

    いただいた情報の例を探したところ、
    きちんとMSDNにありました。(汗)
    自分で探している時には「どんな方法があるか分かっていない」
    ので見つけられませんでした。

    ```lang-c#
    var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
    ```

    ここのindexですね。これを基準にすれば、1つ前などを参照できますね。


    出典元:ラムダ式 (C# プログラミング ガイド)
    https://msdn.microsoft.com/ja-jp/library/bb397687.aspx


    ただし、tkow様も仰る通り、可読性を考えると、
    この方法でLinqを使うのは微妙なのかもしれませんね。


    ちなみにLinqを多次元配列に適用できるようにする件、

    直接的な関数は見つけられなかったのですが、
    先人の皆さんが色々な方法を考え出してくれているようです。

    ・1次元のように扱って良いなら castする。
    ・多次元を維持するなら拡張メソッドを作ってみる。

    などがあるようです。


    出典:
    LINQ で多次元配列を使用する方法
    https://social.msdn.microsoft.com/Forums/ja-JP/e1af278d-2239-4dc7-a3fc-995f3062f658/linq-?forum=csharpgeneralja

    多次元配列を LINQ で簡単に扱おう
    http://blog.xin9le.net/entry/2016/02/17/003605


    ※なお、検索した結果を書かせていただいたのは、
    ココを他の同じ疑問を持った人が見た時のため、
    そして自分が整理するためです。ご了承ください。



    この度は色々なヒントや回答をありがとございました!

    キャンセル

+2

いくつか書きますが、C# は使ったこともないし、実行環境もないので、その点、ご了承くださいませ。

「クラスごと(インスタンスごと、のことかと思います)引数で渡してしまえば~役割分担などで何か間違っているような」とありますが、たとえ情報量の大きなインスタンスだとしても、それが論理的に考えて一つの情報のまとまりとなっているのであれば、そのインスタンスごと引数でやりとりするのはオブジェクト指向的に間違った考えだとは思いません。

クラス設計についてはいろいろな考え方があり、規模感や処理速度などの要求から一概には言えないのですが、他に制約がないのであれば、データを中心に考え、それにしかるべき処理をメソッドとしてつけたものをクラスとしてまとめるのがいいかな、と個人的には思っています。tkow さんが回答の最後に書かれているような設計方針ですね。

「データ読み書き」クラスがデータを保持しているのは、私的にはちょっと気持ちが悪いです。
名前の問題だけかもしれませんが、「データ」クラスがあって、それに「読み書き」メソッドがついている方が自然かな、と。あと、これは occhan さんが teratail に質問としてあげる際に元々の名前をわざと抽象的にしたのかもしれませんが、抽象的な「データ」クラスという名前よりは、たとえば、ファイル A が店舗 A の売り上げデータ、ファイル B が店舗 B の売り上げデータ、で日付ごとの売り上げデータが入っている、というようなものならば「売り上げ」クラスみたいな名前の方がいいのかな、と。
「読み書き」については、ストレージをファイルシステム (CSV) から RDBMS に替えるご予定があるとのことなので、メソッドにするのではなく、「ストレージ」クラスを基底クラスとして、「CSV」クラスと「SQL Server」クラスを派生クラスにするのはありだろうな、と思います(規模的にそこまでやらなくていいケースも多いですが)。「売り上げ」データを読み込む部分では「ストレージ」クラスのインスタンスを使うようにすれば、CSV から SQL Server に替えたときもその部分のコードは変更する必要がなくなりますので。

あと、処理1, 処理2, 処理3 については、これらの「処理機」or「タスク」or「コマンド」をクラス化するクラス設計もあります(これも、ここまでやらなくていいケースが少なくないです)。
つまり、「処理」基底クラスにたとえば exec というメソッドを定義しておき、「処理1」クラス、「処理2」クラス、「処理3」クラスをそれぞれ「処理」クラスの派生クラスにして、実際の処理を exec メソッドをオーバライドする形で作ります。

あとは、具体的なストレージの種類や設定 (SQL Server であれば接続パラメータとか) を渡すとか設定ファイルや環境変数を読み込んで具体的なストレージインスタンスを生成する関数 (下の例では getStorage) や、各売り上げデータに施すべき処理の「タスク」をリストとして返す関数 (下の例では getTasks) を作ったりして、次のようにするとか。

static void main() {
  ストレージ storage = getStorage( /* ここになんか設定とか */ );
  List<処理> tasks = getTasks( /* ここになんか設定とか */ );
  List<売り上げ> saleList = getSaleList( /* なんか */ );
  for (saleList のすべての要素 sale に対して) {
    sale.load(storage);
    for (tasks のすべての要素 task に対して) {
      task.exec(sale);
    }
  }
}

済みません、ちょっと力尽きて最後雑になりました。
おそらくやりたい規模からしたらリッチすぎるやりすぎなクラス構成で、パフォーマンス面ではよくないものですが、クラス設計の考え方をいろいろお知りになりたいご様子でしたので口出しいたしました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/20 22:13


    unau様、ご回答いただき、ありがとうございました!

    また、返信が大変遅くなりまして、誠に申し訳ありません。



    非常に大きな枠組みでのお話をいただき、すごく勉強になりました。

    お陰様で、自分の中で大丈夫な部分と要修正な部分がハッキリとしました。




    情報量が大きいとしても論理的に考えて1つのまとまりなら

    引数として扱っても良い。

    ここが迷っていた原因でもあったので、スッキリしました。



    クラス名に関しては、

    ご指摘の通り簡略化してしまったのですが、

    「データ」クラスに「読み書き」メソッド

    というのが自然なのは大きく頷けますので、

    そのあたりの表現の修正も含めて再構築していきたいと思います。



    またストレージを入れ替える件での方法を教えていただき

    ありがとうございます。

    なるほど、「クラスを派生させる」のは

    機能としては知っていましたが、

    使い方の理解が追いついていなかったので、

    こういう場合に利用すれば良いのですね。

    これから勉強してみます。



    処理の件もクラス化にすると整理されて良さそうですね。

    基底クラスからのオーバーライド、実装してみたいと思います。

    ちなみに処理の種類としては100種類くらいあるのですが、

    その中から条件によって10種類くらいを抜き出して適用させる形になります。

    なので、デリゲートで処理をする関数をリストに入れて、

    それをループで実行させようかな、と考えています。

    (↑勉強途中で書いているので、全くトンチンカンかもしれません。)



    もう少し大きなプロジェクトの場合の考え方を伝授いただき、

    ありがとうございました!

    こういうお話は言語の本とかには載っていない(と思う)ので、

    大変勉強になりました。



    最後に返信が遅くなってしまったこと、

    重ねてお詫びさせていただきます。

    申し訳ありませんでした。


    そして、ありがとうございました!

    キャンセル

  • 2016/04/20 23:05

    処理の数が 100 種類くらいある、そしてその中から 10 種類くらい抜き出して適用する、ということであれば、処理クラスの導入は向いていると思います。

    キャンセル

  • 2016/04/21 21:47

    unau様、ふたたびの回答ありがとうございます!

    処理クラスの導入についてのフォロー助かります。
    詳しい方に後押しされると自信を持って進められますので、
    処理もクラス化して頑張ってみます。

    この度は本当に回答ありがとうございました!

    キャンセル

0

public void データ読み込み (string ファイル名)


細かいことを言うと、こういう処理はstaticでやったほうが処理が早かったりします。
また、この構成だと「Class データ読み書き」がデータの保持もしてしまっているので、

// インスタンス変数
public string d_data = new string [1000];  //データ用配列 (実際は十数個)
public long d_size = 0; // 実際に読み込んだファイルの行数
// インスタンスを生成するstaticメソッド
public static データ読み書き データ読み込み結果取得(string ファイル名){
  データ読み書き d = new データ読み書き();
  // 省略
  while (sr.Peek() > -1)
  {
    d.d_data[d.size] = sr.Readline();  // データ用配列にファイル内容を読み込む
    d.size++;  // 読み込んだ行数をインクリメント - 処理のほうで最終行を知るのに使用
  }
  return d;
}


のように取り扱うとよいかも。

あとは呼び出し側で

データ読み書き d1 = データ読み書き.データ読み込み結果取得(ファイルA);  // データ用配列に読み込む
データ読み書き d2 = データ読み書き.データ読み込み結果取得(ファイルB);  // データ用配列に読み込む
データ読み書き d3 = データ読み書き.データ読み込み結果取得(ファイルC);  // データ用配列に読み込む


みたいにしてやるとd1,d2,d3に読み込み済みデータとデータ行数が設定された状態で取得できますね。

これを対象の処理に引数渡しする分には何も問題ないと思いますが。

// データ処理クラス側の定義
Class データ処理
{
   public void 処理1 (データ読み書き d)
   {
      for(int i = 0; i < d.size; i++){
        // 各行に対する処理1;
      }
      return;
   }
// 略:以下、使う側の記述
  処理1(d1); // ファイルAの読み込み結果に対して処理1を実行

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/15 18:04 編集

    tkturbo様、迅速な回答ありがとうございました。

    大量のデータを引数で受け渡しすることは問題無いのですね。
    安心しました。


    また、static への改善案もありがとうございます。
    (読み込んだ行数へのフォローがさりげなくしてあるところが脱帽です。)

    お陰様でいただいた改善案のコードも反映させ、
    無事に動作させることが出来ました。
    (同じような処理をする場合には、1つのメモリ領域を確保するstaticのほうが
    迅速になる、という理解で宜しいでしょうか?)

    ただ、まだ勉強不足のため、以下の自分が書いたコードと
    データ保持している部分が違うというのが理解できていません。

    一番の相違点は new する場所が
    クラス内なのか、呼び出し側なのか、
    という部分だと思うのですが、
    違いをご教授いただけたら嬉しいです。

    もし、お時間に余裕がありましたら、もう少しお付き合いいただければ幸いです。

    Class 自分
    {
      public string d_data = new string [1000];
      public long d_size = 0; // 実際に読み込んだファイルの行数

      public void データ読み込み(ファイル名)
      {
        while (sr.Peek() > -1)
        {
          d_data[d.size] = sr.Readline(); // データ用配列にファイル内容を読込
          d_size++; // 読み込んだ行数をインクリメント
        }
      }
    }


    Class tkturbo様
    {
      public string d_data = new string [1000];
      public long d_size = 0; // 実際に読み込んだファイルの行数

      public static tkturbo様 データ読み込み結果取得(ファイル名)
      {
        tkturbo様 d = new tkturbo様;
        while (sr.Peek() > -1)
        {
          d.d_data[d.size] = sr.Readline(); // データ用配列にファイル内容を読込
          d.d_size++; // 読み込んだ行数をインクリメント
        }

      return d;
      }
    }


    main
    {

      //自分のクラスの場合
      //データへのアクセス aaa.d_data[i] , aaa.d_size
      自分 aaa = new 自分;
      aaa.データ読み込み(ファイルA);

      //tkturbo様のクラスの場合
      //データへのアクセス bbb.d_data[i] , bbb.d_size

      tkturbo様 bbb = tkturbo様.データ読み込み結果取得(ファイルA);
    }


    もちろん、tkturbo様の記述のほうがスマートなので、
    そちらを使わせていただきたいのですが、
    自分の間違いをもう少し理解したくて書かせていただきました。
    細かい点になることご容赦いただければ幸いです。


    最後にもう1度、ご回答ありがとうございました!

    キャンセル

  • 2016/04/15 18:39

    インスタンスは新規生成(new)されるタイミングで新しいメモリアドレスが割り当てられます。
    私の提示したソースのd1とd2は別アドレスに記憶されるのでデータが入り交じることがないのです。
    また、インスタンスメソッド処理用の領域もインスタンス生成時に確保されるので、不要なインスタンスメソッドを排除することでメモリ使用量が削減できます。
    staticメソッドはクラスがloadされるタイミングでメモリアドレスが割り当てられるのでインスタンスの増加によるメモリへの影響を緩和できるのです。

    キャンセル

  • 2016/04/15 22:23

    tkturbo様、度重なる質問に回答いただき、ありがとうございます。

    なるほど、メモリの増加を抑える効果があるのですね。
    それが(早い以外にも)static を使われた理由なのですね。

    staticを使う。
    クラス内で new する。

    教えていただいたポイントを参考にして、
    もっと勉強していきたいと思います。

    何度もご回答いただき、本当にありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る