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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

3回答

5418閲覧

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

yrmcj

総合スコア12

C#

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

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

2クリップ

投稿2016/09/13 21:11

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

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

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

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

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

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

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

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

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

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

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

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

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

guest

回答3

0

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

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

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

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

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

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

投稿2016/09/13 23:14

編集2016/09/13 23:22
popobot

総合スコア6586

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

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

Panzer_vor

2016/09/13 23:45

> icchiiさん >>> 徐々に作りながらリファクタリングする 特に運用・保守改善がメインとなってくるとコード最適化はかなり重要な要素ですよね。 付け焼き刃な対応が重なると身動きが取れなくなりますし^^;
yrmcj

2016/09/14 15:28

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

0

ベストアンサー

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

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

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

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

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


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

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

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

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

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

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

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

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

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

投稿2016/09/13 22:44

LLman

総合スコア5592

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

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

yrmcj

2016/09/14 15:22

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

0

こんにちは。

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

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

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

C#

1abstract class 印刷 2{ 3 public abstract virtual void print(Employee iEmployee); 4} 5 6abstract class 表彰状印刷 : public 印刷 7{ 8 public string getPrintName(Employee iEmployee) 9 { 10 return iEmployee.Name + "殿"; 11 } 12 (以下略) 13} 14 15class ボウリング大会表彰状 : public 表彰状印刷 16{ 17 public virtual void print(Employee iEmployee) 18 { 19 // getPrintName()やgetPrintAge()を使う 20 ボウリング大会表彰状の印刷処理; 21 } 22 (以下略) 23}

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

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

投稿2016/09/14 01:53

編集2016/09/14 01:55
Chironian

総合スコア23272

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

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

yrmcj

2016/09/14 15:29

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問