많은 사람들이 이미 대답했습니다. 나는 내 자신의 개인적인 관점을 줄 것이라고 생각했습니다.
옛날 옛적에 나는 음악을 만드는 응용 프로그램 (그리고 여전히)에서 일했습니다.
응용 프로그램은 추상적했다 Scale
: 하위 클래스로 클래스를 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
; 슈퍼 클래스 Missile
와 서브 클래스 SpeedRocked
, LandMine
및TrippleExplodingThingy
.
이런 방식으로 생각하는 것은 매우 자연 스럽습니다. 특히 OO를 비교적 처음 접하는 사람에게는 더욱 그렇습니다.
그러나 클래스는 템플릿 이고 객체는 이러한 템플릿에 내용이 담겨 있음을 항상 기억해야합니다 . 템플릿에 원하는 내용을 모두 부어 셀 수없이 많은 가능성을 창출 할 수 있습니다.
템플릿을 채우는 것은 서브 클래스의 일이 아닙니다. 그것은 객체의 일입니다. 서브 클래스의 역할은 실제 기능 을 추가 하거나 템플릿을 확장하는 것입니다. 입니다.
그렇기 때문에 필드가 있는 구체적인 Scale
클래스를 만들고 객체가이 템플릿을 채우Note[]
도록해야 합니다 . 아마도 생성자 또는 무언가를 통해. 결국에는 그렇게했습니다.
클래스에서 템플릿 을 디자인 할 때마다 (예 : Note[]
채워 져야 하는 빈 멤버 또는 String name
값을 할당해야하는 필드) 템플릿을 채우는 것이이 클래스의 객체의 역할 임을 기억하십시오 ( 또는 아마도 이러한 객체를 만드는 사람들). 서브 클래스는 템플릿을 채우지 않고 기능을 추가하기위한 것입니다.
"슈퍼 클래스 Person
, 서브 클래스 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;
}
}
나는 쫓겨났다. 나는 당신이 아이디어를 얻는다고 생각합니다.
서브 클래스는 그들의 슈퍼 클래스에 의해 설정된 템플릿을 채우는 것을 의미하지 않습니다. 서브 클래스는 기능 을 추가하기위한 것 입니다. 개체 는 템플릿을 작성하기위한 것입니다.
가능한 모든 데이터 조합에 대해 새 클래스를 작성해서는 안됩니다. ( Scale
가능한 모든 조합에 대해 새로운 서브 클래스를 생성해서는 안되는 것처럼 Note
).
그녀는 지침입니다. 새로운 서브 클래스를 만들 때마다 수퍼 클래스에 존재하지 않는 새로운 기능이 추가되는지 고려하십시오. 해당 질문에 대한 답변이 "아니오"인 경우 수퍼 클래스의 '템플릿 입력'을 시도하는 것보다 개체를 만드는 것입니다. (그리고 아마도 '사전 설정'이있는 공장은 삶을 더 쉽게 만듭니다).
희망이 도움이됩니다.