Skip to content

Instantly share code, notes, and snippets.

@rotelstift
Created January 28, 2023 02:13
Show Gist options
  • Save rotelstift/f11e5173b12f061dde09d297e4c20156 to your computer and use it in GitHub Desktop.
Save rotelstift/f11e5173b12f061dde09d297e4c20156 to your computer and use it in GitHub Desktop.
良いコード/悪いコードで学ぶ設計入門を読み終わってから https://gist.github.com/rotelstift/33cdbb8b24948534ba573b2d7f007378 をリファクタリングしたコード
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