ผู้คนจำนวนมากตอบไปแล้ว คิดว่าฉันจะให้มุมมองส่วนตัวของฉันเอง
กาลครั้งหนึ่งนานมาแล้วที่ฉันทำงานในแอพ (และยังทำอยู่) ที่สร้างเพลง
แอปพลิเคมีนามธรรมScale
ชั้นเรียนกับหลาย subclasses: CMajor
, DMinor
ฯลฯScale
มองสิ่งที่ต้องการเพื่อ:
public abstract class Scale {
protected Note[] notes;
public Scale() {
loadNotes();
}
// .. some other stuff ommited
protected abstract void loadNotes(); /* subclasses put notes in the array
in this method. */
}
เครื่องกำเนิดเพลงทำงานกับScale
อินสแตนซ์เฉพาะเพื่อสร้างเพลง ผู้ใช้จะเลือกสเกลจากรายการเพื่อสร้างเพลงจาก
อยู่มาวันหนึ่งมีความคิดที่เจ๋ง ๆ มาอยู่ในใจของฉัน: ทำไมไม่อนุญาตให้ผู้ใช้สร้างสเกลของตนเอง ผู้ใช้จะเลือกบันทึกจากรายการกดปุ่มและจะเพิ่มสเกลใหม่ลงในรายการสเกลที่มีอยู่
แต่ฉันไม่สามารถทำสิ่งนี้ได้ นั่นเป็นเพราะเครื่องชั่งทั้งหมดถูกตั้งค่าไว้แล้วในเวลารวบรวม - เนื่องจากมันถูกแสดงเป็นคลาส จากนั้นมันก็กดฉัน:
บ่อยครั้งที่คิดได้ง่ายในแง่ของ 'ซูเปอร์คลาสและคลาสย่อย' เกือบทุกอย่างสามารถแสดงผ่านระบบนี้: ซูเปอร์Person
คลาสJohn
และคลาสย่อยและMary
; ซูเปอร์Car
คลาสVolvo
และคลาสย่อยและMazda
; superclass Missile
และ subclasses SpeedRocked
, และLandMine
TrippleExplodingThingy
เป็นเรื่องธรรมดามากที่จะคิดในลักษณะนี้โดยเฉพาะอย่างยิ่งสำหรับคนที่ค่อนข้างใหม่กับ OO
แต่เราควรจำไว้ว่าการเรียนเป็นแม่แบบและวัตถุที่มีเนื้อหาเทลงในแม่แบบเหล่านี้ คุณสามารถเทเนื้อหาที่คุณต้องการลงในเทมเพลตได้
ไม่ใช่หน้าที่ของคลาสย่อยเพื่อเติมเทมเพลต มันเป็นงานของวัตถุ งานของ subclass คือการเพิ่มฟังก์ชันการทำงานที่เกิดขึ้นจริงหรือขยายแม่แบบ
และนั่นคือเหตุผลที่ผมควรจะได้สร้างคอนกรีตScale
ชั้นที่มีNote[]
ข้อมูลและให้วัตถุกรอกข้อมูลลงในแม่แบบนี้ ; อาจผ่านตัวสร้างหรือบางสิ่งบางอย่าง และในที่สุดฉันก็ทำเช่นนั้น
ทุกครั้งที่คุณออกแบบเทมเพลตในคลาส (เช่นNote[]
สมาชิกว่างที่ต้องเติมหรือString name
ฟิลด์ที่ต้องกำหนดค่า) โปรดจำไว้ว่ามันเป็นงานของวัตถุของคลาสนี้เพื่อเติมเทมเพลต ( หรือผู้ที่สร้างวัตถุเหล่านี้) คลาสย่อยนั้นมีจุดประสงค์เพื่อเพิ่มการใช้งานไม่ใช่เพื่อเติมเทมเพลต
คุณอาจถูกล่อลวงให้สร้าง "superclass Person
, subclasses John
และMary
" ชนิดของระบบเหมือนที่คุณทำเพราะคุณชอบความเป็นทางการที่จะทำให้คุณได้รับ
วิธีนี้คุณก็สามารถพูดแทนPerson p = new Mary()
Person p = new Person("Mary", 57, Sex.FEMALE)
มันทำให้สิ่งต่าง ๆ เป็นระเบียบมากขึ้นและมีโครงสร้างมากขึ้น แต่อย่างที่เราพูดการสร้างคลาสใหม่สำหรับการรวมกันของข้อมูลทุกอย่างนั้นไม่ใช่วิธีการที่ดีเพราะมันจะขยายโค้ดเพื่ออะไรและ จำกัด คุณในแง่ของความสามารถในการใช้งานจริง
ดังนั้นนี่คือวิธีการแก้ปัญหา: ใช้โรงงานพื้นฐานหรืออาจเป็นแบบคงที่ ชอบมาก
public final class PersonFactory {
private PersonFactory() { }
public static Person createJohn(){
return new Person("John", 40, Sex.MALE);
}
public static Person createMary(){
return new Person("Mary", 57, Sex.FEMALE);
}
// ...
}
ด้วยวิธีนี้คุณสามารถใช้ 'ที่ตั้งไว้ล่วงหน้า' 'มาพร้อมกับโปรแกรม' ได้อย่างง่ายดายเช่น: Person mary = PersonFactory.createMary()
แต่คุณยังสงวนสิทธิ์ในการออกแบบบุคคลใหม่แบบไดนามิกตัวอย่างเช่นในกรณีที่คุณต้องการอนุญาตให้ผู้ใช้ทำเช่นนั้น . เช่น:
// .. requesting the user for input ..
String name = // user input
int age = // user input
Sex sex = // user input, interpreted
Person newPerson = new Person(name, age, sex);
หรือดียิ่งขึ้น: ทำอะไรเช่นนั้น:
public final class PersonFactory {
private PersonFactory() { }
private static Map<String, Person> persons = new HashMap<>();
private static Map<String, PersonData> personBlueprints = new HashMap<>();
public static void addPerson(Person person){
persons.put(person.getName(), person);
}
public static Person getPerson(String name){
return persons.get(name);
}
public static Person createPerson(String blueprintName){
PersonData data = personBlueprints.get(blueprintName);
return new Person(data.name, data.age, data.sex);
}
// .. or, alternative to the last method
public static Person createPerson(String personName){
Person blueprint = persons.get(personName);
return new Person(blueprint.getName(), blueprint.getAge(), blueprint.getSex());
}
}
public class PersonData {
public String name;
public int age;
public Sex sex;
public PersonData(String name, int age, Sex sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}
ฉันถูกพาไป ฉันคิดว่าคุณได้รับความคิด
คลาสย่อยไม่ได้หมายถึงการเติมแม่แบบที่กำหนดโดยซูเปอร์คลาสของพวกเขา subclasses จะหมายถึงการเพิ่มฟังก์ชันการทำงาน วัตถุนั้นมีจุดประสงค์เพื่อเติมข้อมูลในเทมเพลตนั่นคือสิ่งที่พวกเขาทำ
คุณไม่ควรสร้างคลาสใหม่สำหรับชุดข้อมูลที่เป็นไปได้ทั้งหมด (เช่นเดียวกับที่ฉันไม่ควรสร้างScale
คลาสย่อยใหม่สำหรับทุกชุดที่เป็นไปได้Note
)
นี่เป็นแนวทาง: เมื่อใดก็ตามที่คุณสร้างคลาสย่อยใหม่ให้พิจารณาว่ามันเพิ่มฟังก์ชั่นใหม่ที่ไม่มีอยู่ในซูเปอร์คลาสหรือไม่ หากคำตอบสำหรับคำถามนั้นคือ "ไม่" คุณอาจลอง 'กรอกข้อมูลแม่แบบ' ของซูเปอร์คลาสซึ่งในกรณีนี้เพียงแค่สร้างวัตถุ (และอาจเป็นโรงงานที่มี 'สถานี' เพื่อทำให้ชีวิตง่ายขึ้น)
หวังว่าจะช่วย