Created
January 28, 2023 02:13
-
-
Save rotelstift/f11e5173b12f061dde09d297e4c20156 to your computer and use it in GitHub Desktop.
良いコード/悪いコードで学ぶ設計入門を読み終わってから https://gist.github.com/rotelstift/33cdbb8b24948534ba573b2d7f007378 をリファクタリングしたコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Random; | |
public class Main { | |
/** | |
* あるお店にかけられた問い合わせ電話の応対をシミュレートするコード | |
* | |
* 客からの電話にまず店員が出て質問内容を聞いて答える。 | |
* もし自分では答えられない内容だったら店長に取り次ぐ。 | |
* | |
* しかし、店長が忙しくて電話に出られない時は、 | |
* 客の電話番号を聞いて折り返すと伝えて終了する。 | |
* @param args | |
*/ | |
public static void main(String[] args){ | |
Caller customer = new Caller( | |
"Charley", | |
new TelephoneNumber("03-1234-1234") | |
); | |
Staff staff = new Staff("Alice"); | |
Manager manager = new Manager("Bob"); | |
Telephone phone = Telephone.callOn(customer, staff); | |
phone.greeting(); | |
phone.askName(); | |
phone.askInquiryAbout(); | |
if (phone.receiver.canAnswer()) { | |
phone.answerInquiryAbout(); | |
} else if(manager.isNotBusy()) { | |
phone = phone.takenOverReceiver(manager); | |
phone.askInquiryAbout(); | |
phone.answerInquiryAbout(); | |
} else { | |
phone.callBack(); | |
phone.callOffWithCallBack(); | |
return; | |
} | |
phone.callOff(); | |
return; | |
} | |
} | |
class Telephone { | |
Caller caller; | |
Receiver receiver; | |
private Telephone(final Caller caller, final Receiver receiver) { | |
if (caller == null || receiver == null) { | |
throw new IllegalArgumentException(); | |
} | |
this.caller = caller; | |
this.receiver = receiver; | |
} | |
public static Telephone callOn(final Caller caller, final Receiver receiver) { | |
return new Telephone(caller, receiver); | |
} | |
public Telephone takenOverReceiver(final Receiver receiver) { | |
this.receiver.sayPassThePhone(); | |
receiver.sayBehalf(); | |
return new Telephone(this.caller, receiver); | |
} | |
protected void greeting() { | |
this.caller.sayHello(); | |
this.receiver.sayHello(); | |
} | |
protected void askName() { | |
this.receiver.sayAskName(); | |
this.caller.sayAnswerName(); | |
} | |
protected void askInquiryAbout() { | |
this.receiver.sayAskInquiryAbout(); | |
this.receiver.inquiry = this.caller.inquiry; | |
this.caller.sayAskedInquiry(); | |
} | |
protected void answerInquiryAbout() { | |
this.receiver.sayAnswerAskedInquiry(); | |
} | |
protected void callBack() { | |
this.receiver.sayCallBack(); | |
this.caller.sayAnsweredTelephoneNumber(); | |
} | |
protected void callOffWithCallBack() { | |
this.caller.sayByeWithCallBack(); | |
this.receiver.sayBye(); | |
System.out.println("ガチャン(電話を切る音)"); | |
} | |
protected void callOff() { | |
this.caller.sayBye(); | |
this.receiver.sayBye(); | |
System.out.println("ガチャン(電話を切る音)"); | |
} | |
} | |
abstract class Talker { | |
protected String name; | |
protected Inquiry inquiry; | |
protected void sayHello() { | |
this.talking(hello()); | |
} | |
protected void sayBye() { | |
this.talking(bye()); | |
} | |
protected void talking(final String talking) { | |
String script = this.name + " : " + talking; | |
System.out.println(script); | |
} | |
abstract protected String hello(); | |
abstract protected String bye(); | |
} | |
class TelephoneNumber { | |
final String number; | |
TelephoneNumber(final String number) { | |
if (!number.matches("^[0-9]{2,4}-[0-9]{2,4}-[0-9]{4}$")) { | |
throw new IllegalArgumentException("電話番号が正しくありません"); | |
} | |
this.number = number; | |
} | |
} | |
class Caller extends Talker { | |
final TelephoneNumber phoneNumber; | |
final Inquiry inquiry; | |
final Map<InquiryType, Inquiry> inquiries = new HashMap<>(); | |
Caller(final String name, final TelephoneNumber phoneNumber) { | |
if (name == null || phoneNumber == null) { | |
throw new IllegalArgumentException(); | |
} | |
this.name = name; | |
this.phoneNumber = phoneNumber; | |
this.inquiry = setInquiries(); | |
} | |
/** | |
* Caller が問い合わせたい内容をランダムに決めるメソッド | |
* 問い合わせたい内容が増減した時にはここも変更する | |
* @return InquiryType | |
*/ | |
private InquiryType makeAskedInquiryType() { | |
InquiryType[] inquiryTypes = new InquiryType[3]; | |
inquiryTypes[0] = InquiryType.shopClosing; | |
inquiryTypes[1] = InquiryType.shopAddress; | |
inquiryTypes[2] = InquiryType.reserveCourse; | |
Random randomObject = new Random(); | |
return inquiryTypes[randomObject.nextInt(3)]; | |
} | |
/** | |
* Caller が問い合わせたい内容をセットするメソッド | |
* 問い合わせたい内容が増減した時にはここも変更する | |
*/ | |
private Inquiry setInquiries() { | |
inquiries.put(InquiryType.shopClosing, new InquiryShopClosing()); | |
inquiries.put(InquiryType.shopAddress, new InquiryShopAddress()); | |
inquiries.put(InquiryType.reserveCourse, new InquiryReserveCourse()); | |
return inquiries.get(makeAskedInquiryType()); | |
} | |
protected InquiryType askedInquiryType() { | |
return this.inquiry.type(); | |
} | |
protected void sayAskedInquiry() { | |
this.talking(askedInquiry()); | |
} | |
protected void sayByeWithCallBack() { | |
this.talking(byeWithCallBack()); | |
} | |
protected void sayAnswerName() { | |
this.talking(answerName()); | |
} | |
protected void sayAnsweredTelephoneNumber() { | |
this.talking(answeredTelephoneNumber()); | |
} | |
@Override | |
protected String hello() { | |
return "もしもし?"; | |
} | |
@Override | |
protected String bye() { | |
return "ありがとうございます。それでは失礼します。"; | |
} | |
private String askedInquiry() { | |
return this.inquiry.asked(); | |
} | |
private String byeWithCallBack() { | |
return "よろしくお願いします。それでは失礼します。"; | |
} | |
private String answerName() { | |
return this.name + "です。"; | |
} | |
private String answeredTelephoneNumber() { | |
return this.phoneNumber.number + "です。"; | |
} | |
} | |
abstract class Receiver extends Talker { | |
final Map<InquiryType, Knowledge> knowledge = new HashMap<>(); | |
protected Boolean canAnswer() { | |
Knowledge answer = knowledge.get(inquiry.type()); | |
if (answer == null) { | |
return false; | |
} | |
return true; | |
} | |
protected void sayPassThePhone() { | |
this.talking(passThePhone()); | |
} | |
protected void sayBehalf() { | |
this.talking(behalf()); | |
} | |
protected void sayAnswerAskedInquiry() { | |
this.talking(answerAskedInquiry()); | |
} | |
protected void sayCallBack() { | |
this.talking(callBack()); | |
} | |
protected void sayAskName() { | |
this.talking(askName()); | |
} | |
protected void sayAskInquiryAbout() { | |
this.talking(askInquiryAbout()); | |
} | |
protected String answerAskedInquiry() { | |
return knowledge.get(inquiry.type()).answer(); | |
} | |
@Override | |
protected String hello() { | |
return "もしもし、都会の隠れ家亭です。"; | |
} | |
protected String passThePhone() { | |
return "ただいま電話を代わります。少々お待ちください。"; | |
} | |
protected String behalf() { | |
return "お電話代わりました。" + this.name + "です。"; | |
} | |
protected String callBack() { | |
return "折り返してご連絡します。"; | |
} | |
protected String askName() { | |
return "お名前をお伺いしてもよろしいでしょうか?"; | |
} | |
protected String askInquiryAbout() { | |
return "ご用件をお聞かせください。"; | |
} | |
} | |
class Staff extends Receiver { | |
Staff(final String name) { | |
if (name == null) { | |
throw new IllegalArgumentException(); | |
} | |
this.name = name; | |
knowledge.put(InquiryType.shopClosing, new AnswerShopClosing()); | |
knowledge.put(InquiryType.shopAddress, new AnswerShopAddress()); | |
} | |
@Override | |
protected String bye() { | |
return this.name + "が承りました。それでは失礼します。"; | |
} | |
@Override | |
protected String callBack() { | |
return "調べて後ほど折り返しますので、お電話番号をお聞かせください。"; | |
} | |
} | |
class Manager extends Receiver { | |
final Boolean isBusy; | |
Manager(final String name) { | |
if (name == null) { | |
throw new IllegalArgumentException(); | |
} | |
this.name = name; | |
knowledge.put(InquiryType.shopClosing, new AnswerShopClosing()); | |
knowledge.put(InquiryType.shopAddress, new AnswerShopAddress()); | |
knowledge.put(InquiryType.reserveCourse, new AnswerReseveCourse()); | |
Random randomObject = new Random(); | |
isBusy = randomObject.nextBoolean(); | |
} | |
@Override | |
protected String behalf() { | |
return "もしもし、お電話代わりました。店長の" + this.name + "です。"; | |
} | |
@Override | |
protected String bye() { | |
return this.name + "が承りました。それでは失礼します。"; | |
} | |
Boolean isNotBusy() { | |
return !this.isBusy; | |
} | |
} | |
enum InquiryType { | |
shopClosing, | |
shopAddress, | |
reserveCourse | |
} | |
interface Inquiry { | |
InquiryType type(); | |
String asked(); | |
} | |
class InquiryShopClosing implements Inquiry { | |
final InquiryType type; | |
final String inquiry; | |
InquiryShopClosing() { | |
this.type = InquiryType.shopClosing; | |
this.inquiry = "閉店時間は何時ですか?"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String asked() { | |
return this.inquiry; | |
} | |
} | |
class InquiryShopAddress implements Inquiry { | |
final InquiryType type; | |
final String inquiry; | |
InquiryShopAddress() { | |
this.type = InquiryType.shopAddress; | |
this.inquiry = "お店の場所はどこですか?"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String asked() { | |
return this.inquiry; | |
} | |
} | |
class InquiryReserveCourse implements Inquiry { | |
final InquiryType type; | |
final String inquiry; | |
InquiryReserveCourse() { | |
this.type = InquiryType.reserveCourse; | |
this.inquiry = "予約できるコースを教えてください。"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String asked() { | |
return this.inquiry; | |
} | |
} | |
interface Knowledge { | |
InquiryType type(); | |
String answer(); | |
} | |
class AnswerShopClosing implements Knowledge { | |
final InquiryType type; | |
final String answer; | |
AnswerShopClosing() { | |
this.type = InquiryType.shopClosing; | |
this.answer = "23時です。"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String answer() { | |
return this.answer; | |
} | |
} | |
class AnswerShopAddress implements Knowledge { | |
final InquiryType type; | |
final String answer; | |
AnswerShopAddress() { | |
this.type = InquiryType.shopAddress; | |
this.answer = "駅の東口のすぐ近くです。"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String answer() { | |
return this.answer; | |
} | |
} | |
class AnswerReseveCourse implements Knowledge { | |
final InquiryType type; | |
final String answer; | |
AnswerReseveCourse() { | |
this.type = InquiryType.reserveCourse; | |
this.answer = "春のフレンチディナーが予約できます。"; | |
} | |
public InquiryType type() { | |
return this.type; | |
} | |
public String answer() { | |
return this.answer; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment