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

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

ただいまの
回答率

87.37%

継承かコンポジションか拡張メソッドか(それ以外か)の選択

解決済

回答 3

投稿

  • 評価
  • クリップ 2
  • VIEW 4,509

score 12

Employeeクラスがあり
string Nameプロパティと
date? Birthdayプロパティがあるとします。

表彰状を印刷するためのクラス(ボウリング大会表彰状クラス、マラソン部表彰状クラスなど)では
Employeeオブジェクトを
Nameプロパティに+"殿"
Birthdayから年齢を算出して+"歳"(null値の場合は、"??歳")
にして使う

公的文書印刷クラスでは
Nameプロパティはそのまま
Birthdayは、和暦表示(null値の場合は空白)
にして使う

このような場合は、印刷クラスとEmployeeクラスの間に中間的な処理が必要になると思いますが、
この場合の中間的な処理には何を使ったらいいでしょうか?

自分が思いついたのは
・継承
・コンポジション(Employeeオブジェクトを保持するプロパティを持つクラスを作成し、
必要な分だけReadonlyなNameForPrintingsといったプロパティを作成する)
・名前空間を分けた拡張メソッドを作成し、印刷クラスでは名前空間のインポートを変える

継承は、はじめ安易に思いついたのですが、ダウンキャストになるのでそもそも不適切
コンポジションは、Employeeがたくさんのプロパティを持ち大半が処理をする必要がない
(stringでそのまま出力をするプロパティが大半な)場合、付け足す処理はほんの一部なのに、
いちいちプロパティを作り直すのが面倒
拡張メソッドは、いいアイデアだと思ったのですが、あまり例を見ない気がします

皆様ならどのように中間的な処理を行うクラスなどを作成しますでしょうか?

現在、独学に近い状態で設計からコーディングまでしなければならない状況にあります。
リーダブル・コードや、Code Complete、デザインパターンに関する本などを読んでみましたが、
実務では、どう適用していいかわからず議論の相手もいない状態で一人でいつも悩んでいます。
(悩んだ挙句、結局時間に追われて
恥ずかしながらただ目先の要求を満たすだけの汚いコードになることもしばしば)
オススメの本や学習方法などありましたら、あわせてご回答いただければ嬉しいです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+1

皆様ならどのように中間的な処理を行うクラスなどを作成しますでしょうか?

私でしたらまず、種類の多い印刷クラスを、委譲か継承で整理したいと思います。

デザインパターンで言うと、「ストラテジー」か「テンプレートメソッド」パターンです。
つまり、表彰状印刷や公的文書印刷のクラスを、印刷クラスから体系的に派生させます。

ご質問の「中間的な処理」は、もしプログラムの規模が大きければ、
年齢算出や和暦表示も、日付や時間を扱うクラス群に統合します。

しかし逆に、規模が小さければ、メソッドで済ませるかもしれません。
「殿」を表彰状でしか使わないなら、表彰状印刷クラスのメソッドで処理します。


実務では、どう適用していいかわからず
目先の要求を満たすだけの汚いコードになる

実務では開発リソースが足りない場面が多いので、
実務的なOOでは「選択と集中」が重要になると考えます。

オブジェクト指向(設計)は都市計画のようなものです。

日本全国を大都市にするのは現実的に不可能なように、
コード全体を完全なOOにしようとするのは非現実的です。
もちろん、全部完全が理想ですが、「完璧は良さの敵」です。

会計なら金額が中心、日程管理なら日付が中心、
社員管理や顧客管理なら人間とその情報が中心、
と中心を明確にして設計していくことが重要です。

大都市のインフラが充実しているのと同じで、
そうしたドメインの中心に近い部分は手をかけます。
周辺は汚くてもいいですが、中心はキレイにします。

クラス化、パッケージ化、ライブラリ化、DSL化、値の不変化、
デザパタの適用、テスト自動化、リファクタリング、……などなど、
中心部分は周辺部分よりもコストをかけて整備します。

オススメの本や学習方法など

今言った「ドメイン」の考え方について学習するには、
「DDD(ドメイン駆動設計)」に関する本やサイトがオススメです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/09/15 00:22

    全てが教科書的なパターンで綺麗に書けるようになるのが理想だと思っていた節があったので、メリハリが大事、というドメインの考え方にハッとさせられました。ありがとうございます。

    キャンセル

+1

自分なら中間処理する別のクラスを作りますかね
Employeeクラスや印刷系のクラスはライブラリに近いので、他のクラスと結合しすぎず、独立したものとしておきます。

その代わり、中間処理するクラスは、それらのクラスを使う側なので、あまりクラス設計に凝らずに作ります。
中間処理するクラスをどういうふうにまとめるかは、最終的にどういうことをやりたいかによって変わってくるかと

印刷系クラスの引数にEmployeeを渡すぐらいするかもしれませんが、その場合Employeeに似たGuestなどが登場する可能性があるかなどを考慮してインターフェース化するかもしれません。

同様に印刷系のクラスも似たようなクラスをまとめて、インタフェースや基底クラスを作ると思います。

ちなみに、クラス設計を勉強する方法ですが、個人的には、よくできたアプリのコードを読むことだと思います。
アプリに限らず、ライブラリでもいいですが、普段使っているもののコードを読むと、クラスのまとめ方など勉強になります。

補足
ちなみに自分は一時期デザインパターンなどの本を読みましたが、あまり参考にしていません。
むしろ、現在の要件に対して、どうのようにクラスをまとめたら、
再利用性が高くて、依存関係が少なく、拡張性が高いかを常に考えて実装しています。
また、初めからガチガチにクラス設計するというよりは、
徐々に作りながらリファクタリングするようなプログラミングをやっているように思います。
※ただし、自分は自社開発だからかもしれません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/09/14 08:45

    > icchiiさん
    >>> 徐々に作りながらリファクタリングする

    特に運用・保守改善がメインとなってくるとコード最適化はかなり重要な要素ですよね。

    付け焼き刃な対応が重なると身動きが取れなくなりますし^^;

    キャンセル

  • 2016/09/15 00:28

    >>常に考えて実装しています。

    これが重要なんですね。コードを読むというのも、
    今までは敷居が高い感じがして避けていたのですが、
    是非やろうと思います。ありがとうございます。

    キャンセル

0

こんにちは。

印刷は例えば下記のような抽象関係になると思います。

ボウリング大会表彰状印刷 → 表彰状印刷 → 印刷

ですので、私なら下記のような構造にすると思います。

abstract class 印刷
{
    public abstract virtual void print(Employee iEmployee);
}

abstract class 表彰状印刷 : public 印刷
{
    public string getPrintName(Employee iEmployee)
    {
        return iEmployee.Name + "殿";
    }
    (以下略)
}

class ボウリング大会表彰状 : public 表彰状印刷
{
    public virtual void print(Employee iEmployee)
    {
        // getPrintName()やgetPrintAge()を使う
        ボウリング大会表彰状の印刷処理;
    }
    (以下略)
}


更に、EmployeeはParsonを派生したクラスとし印刷クラス群に渡すものはParsonオブジェクトにするだろうと思います。

iEmployeeはパラメータではなく印刷クラスのメンバ変数としてコンストラクタで設定することもあるかもしれません。印刷とEmployeeやParsonの関係が薄いので、しない可能性も高そうですが。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/09/15 00:29

    具体的なコードをあげての回答はわかりやすく参考になりました。ありがとうございました。

    キャンセル

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

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

関連した質問

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