![แนวคิด OOP ใน Java - 1](https://cdn.codegym.cc/images/article/937955ff-0a01-4de5-b641-1c6f5fbcbd12/800.jpeg)
วัตถุ อ็อบเจ็กต์ Java และอ็อบเจ็กต์ในโลกแห่งความเป็นจริงมีสองลักษณะ: สถานะและพฤติกรรม ตัวอย่างเช่น วัตถุของมนุษย์มีสถานะ (ชื่อ เพศ นอนหรือไม่...) และพฤติกรรม (ศึกษา Java เดิน พูด...) ออบเจกต์ Java ใด ๆ จะเก็บสถานะของมันไว้ในฟิลด์และแสดงพฤติกรรมของมันผ่านเมธอด |
การห่อหุ้ม
การห่อหุ้มข้อมูลเป็นการซ่อนข้อมูลภายในจากโลกภายนอก และเข้าถึงข้อมูลได้โดยวิธีการที่เปิดเผยต่อสาธารณะเท่านั้น นั่นหมายความว่าอย่างไร? ข้อมูลอะไร? ซ่อนตัวจากใคร? การซ่อนหมายถึงการจำกัดการเข้าถึงโดยตรงไปยังสมาชิกข้อมูล (ฟิลด์) ของคลาสมันทำงานอย่างไรใน Java:
- ฟิลด์ถูกทำให้เป็นส่วนตัว
- แต่ละฟิลด์ในคลาสจะมีเมธอดพิเศษสองเมธอด: ตัวรับและตัวเซ็ต เมธอด Getter ส่งกลับค่าของฟิลด์ เมธอด Setter ให้คุณเปลี่ยนค่าของฟิลด์ด้วยวิธีทางอ้อมแต่อนุญาต
ตัวอย่างการห่อหุ้มในโค้ด Java:
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this: firstStudent.name = "John";
}
}
ทำไมคุณจึงควรใช้การห่อหุ้ม?
เหตุผลหลักคือเพื่อให้ง่ายต่อการเปลี่ยนรหัสของคุณ ลองจินตนาการว่าคุณมีใบสมัครสำหรับโรงเรียนสอนฮอกกี้ และมี ชั้นเรียน HockeyStudentที่มีสองฟิลด์ที่เก็บชื่อและอายุของนักเรียนเมื่อเขาหรือเธอลงทะเบียนเรียนที่โรงเรียน สิ่งนี้:public class HockeyStudent {
public String name;
public int ageOfEnrollment;
}
ฟิลด์ageOfEnrollmentเป็นแบบสาธารณะ ไม่มี getters หรือ setters... คลาสนี้ถูกใช้โดยคลาสอื่น ๆ และทุกอย่างเรียบร้อยดีจนกระทั่งนักพัฒนาบางคนตัดสินใจว่าฟิลด์ int เดียวไม่เพียงพอ นักกีฬาฮอกกี้บางคนในกลุ่มมีอายุมากกว่าเพื่อนรุ่นเดียวกันเกือบหนึ่งปี ดังนั้นจะสะดวกกว่าที่จะแบ่งพวกเขาออกเป็นสองกลุ่มโดยขึ้นอยู่กับเดือนที่พวกเขาเกิด ดังนั้นควรเปลี่ยนฟิลด์ageOfEnrollment เป็น int array (int[][]) : ตัวเลขแรกคือปีเต็มและตัวเลขที่สองคือเดือน ตอนนี้คุณต้อง refactor รหัสทั้งหมดที่ใช้ คลาส Student ! แต่ถ้าอายุ ของคุณลงทะเบียนเรียนฟิลด์เป็นแบบส่วนตัวและคุณมีตัวรับและตัวตั้ง แล้วทุกอย่างก็ง่ายขึ้น หากข้อกำหนดสำหรับการตั้งค่าอายุของนักเรียนเปลี่ยนไป เพียงอัปเดตตรรกะใน เมธอด setAgeOfEnrollment() setter และชั้นเรียนของคุณสามารถใช้Student ต่อไปได้ โดยไม่มีปัญหาใดๆ! ตัวอย่างนี้ค่อนข้างมีการประดิษฐ์ แต่ฉันหวังว่ามันจะอธิบายได้ว่าทำไมการใช้การห่อหุ้มจึงเป็นแนวคิดที่ดี
มรดก
หลักการนี้เข้าใจได้ง่ายกว่าแม้ไม่มีประสบการณ์จริง อย่าทำซ้ำตัวเอง (DRY) อาจเป็นคติของแนวคิดการสืบทอด การสืบทอดช่วยให้คุณสร้างคลาสย่อยที่สืบทอดฟิลด์และเมธอดของคลาสพาเรนต์โดยไม่ต้องกำหนดใหม่ แน่นอน คุณสามารถแทนที่ฟิลด์และเมธอดของคลาสพาเรนต์ในคลาสย่อยได้ แต่ไม่จำเป็น ยิ่งไปกว่านั้น คุณสามารถเพิ่มสถานะและพฤติกรรมใหม่ในคลาสย่อยได้ คลาสพาเรนต์บางครั้งเรียกว่าซูเปอร์คลาสหรือคลาสพื้นฐาน และคลาสย่อยเรียกว่าคลาสย่อย คำหลัก ขยายของ Java ใช้เพื่อนำหลักการสืบทอดในรหัสไปใช้มันทำงานอย่างไรใน Java:
- สร้างคลาสหลัก
- สร้างคลาสลูกโดยใช้คำสำคัญขยาย
- ใน Constructor ของคลาส Child ให้ใช้ เมธอด super(parentField1, parentField2, ...)เพื่อตั้งค่าฟิลด์ของพาเรนต์
ตัวสร้างเป็นวิธีพิเศษที่ใช้ในการเริ่มต้นวัตถุที่สร้างขึ้นใหม่ ตัวสร้างมีชื่อเดียวกับชื่อคลาส ตัวสร้างมีสองประเภท: ตัวสร้างเริ่มต้น (ตัวสร้างแบบไม่มีอาร์กิวเมนต์) และตัวสร้างแบบกำหนดพารามิเตอร์ คลาสต้องมีตัวสร้างอย่างน้อยหนึ่งตัว (มีตัวสร้างเริ่มต้นหากไม่ได้กำหนดตัวสร้างอื่น) และสามารถมีได้หลายตัว ทุกครั้งที่คุณสร้างวัตถุใหม่ คุณจะเรียกตัวสร้างวัตถุนั้น ในตัวอย่างด้านบน คุณทำสิ่งนี้ในบรรทัดนี้:
คุณใช้ คีย์เวิร์ด ใหม่เพื่อเรียก ตัวสร้างเริ่มต้นของคลาส Student : tudent( ) |
กฎบางอย่าง:
- หนึ่งชั้นเรียนสามารถมีผู้ปกครองได้เพียงหนึ่งคนเท่านั้น
- คลาสผู้ปกครองหนึ่งคลาสสามารถมีคลาสย่อยได้หลายคลาส
- คลาสย่อยสามารถมีคลาสย่อยของตัวเองได้
ตัวอย่างการสืบทอดในโค้ด Java
มาสร้างคลาส โทรศัพท์ กันเถอะpublic class Phone {
int price;
double weight;
// Constructor
public Phone(int price, double weight) {
this.price = price;
this.weight = weight;
}
void orderPhone(){
System.out.println("Ordering phone...");
}
}
แน่นอนว่ามีโทรศัพท์หลายประเภท ดังนั้นเรามาสร้างคลาสย่อยสองคลาส: คลาสหนึ่งสำหรับโทรศัพท์ Android และอีกคลาสสำหรับ iPhone จากนั้นเราจะเพิ่มฟิลด์และวิธีการบางอย่างที่พาเรนต์ไม่มี และเราจะใช้super()เพื่อเรียกตัวสร้างเพื่อเริ่มต้นฟิลด์ที่คลาสพาเรนต์มี
ตัวอย่างการสืบทอดใน Java
public class Android extends Phone {
// Some new fields
String androidVersion;
int screenSize;
String secretDeviceCode;
// Constructor
public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
super(price, weight); // Android inherits Phone’s fields
//this - reference to the current object
//super - reference to the parent object
this.androidVersion = androidVersion;
this.screenSize = screenSize;
this.secretDeviceCode = secretDeviceCode;
}
// New Android-specific method, does not exist in the Phone class
void installNewAndroidVersion() {
System.out.println("installNewAndroidVersion invoked...");
}
}
public class IPhone extends Phone {
boolean fingerPrint;
public IPhone(int price, double weight, boolean fingerPrint) {
super(price, weight);
System.out.println("IPhone constructor was invoked...");
this.fingerPrint = fingerPrint;
}
void deleteIPhoneFromDb() {
System.out.println("deleteIPhoneFromDb invoked...");
}
@Override // This is about polymorphism, see below
void orderPhone(){
System.out.println("Ordering my new iPhone and deleting the old one...");
}
}
ดังนั้น พูดซ้ำ: ใน Java การสืบทอดจะให้คุณขยายคลาสด้วยคลาสย่อยที่สืบทอดฟิลด์และเมธอดของคลาสพาเรนต์ เป็นวิธีที่ยอดเยี่ยมในการนำโค้ดกลับมาใช้ใหม่ได้
ความหลากหลาย
ความแตกต่างหลากหลายคือความสามารถของวัตถุในการแปรสภาพ โดยมีรูปแบบที่แตกต่างกันหรือแสดงในรูปแบบที่แตกต่างกัน ใน Java ความหลากหลายมักจะเกิดขึ้นเมื่อการอ้างอิงคลาสพาเรนต์ถูกใช้เพื่ออ้างถึงอ็อบเจกต์คลาสลูกความหมายและวิธีการทำงานใน Java:
ความหลากหลายใน Java คืออะไร? โดยทั่วไป หมายความว่าคุณสามารถใช้ชื่อเมธอดเดียวกันเพื่อวัตถุประสงค์ที่แตกต่างกันได้ มีความแตกต่างสองประเภทใน Java: การแทนที่เมธอด (ความหลากหลายแบบไดนามิก) และการโอเวอร์โหลดเมธอด (ความหลากหลายแบบสแตติก)วิธีการเอาชนะ
คุณสามารถแทนที่เมธอดของคลาสพาเรนต์ในคลาสย่อยได้ โดยบังคับให้เมธอดทำงานด้วยวิธีอื่น มาสร้าง คลาสผู้ปกครอง Musicianด้วยเมธอดplay()ตัวอย่างของ polymorphism ในโค้ด Java
public class Musician {
String name;
int age;
// Default constructor
public Musician() {
}
// Parameterized constructor
public Musician(String name, int age) {
this.name = name;
this.age = age;
}
void play() {
System.out.println("I am playing my instrument...");
}
}
นักดนตรีต่างใช้เครื่องดนตรีต่างกัน มาสร้างคลาสย่อยสองคลาส: นักเปียโนและนักไวโอลิน ด้วยความหลากหลาย แต่ละคนจะใช้เมธอดplay() เวอร์ชันของตัวเอง เมื่อแทนที่ คุณสามารถใช้ คำอธิบายประกอบ @Overrideได้ แต่ไม่จำเป็น
public class Pianist extends Musician {
String favoritePianoType;
public Pianist(String name, int age, String favoritePianoType) {
super(name, age);
this.favoritePianoType = favoritePianoType;
}
@Override
void play(){
System.out.println("I am playing the piano...");
}
}
ผู้เล่นไวโอลินสามารถเป็นศิลปินเดี่ยวหรือเป็นสมาชิกของวงออร์เคสตราได้ ลองพิจารณาดูเมื่อแทนที่เมธอดplay () ของเรา
public class Violinist extends Musician {
boolean isSoloist;
public Violinist(String name, int age, boolean isSoloist) {
super(name, age);
this.isSoloist = isSoloist;
}
@Override
void play(){
if (isSoloist)
System.out.println("I am playing the violin solo...");
else
System.out.println("I am playing the violin in an orchestra...");
}
}
มาสร้าง คลาส Demoกัน ซึ่งเราจะสร้างวัตถุสามอย่าง หนึ่งอินสแตนซ์ของแต่ละคลาสที่สร้างไว้ก่อนหน้านี้ เราจะดูว่าเราได้ผลลัพธ์อะไร
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 32, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
}
}
นี่คือสิ่งที่เราได้รับ:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
นักไวโอลินและนักเปียโนทุกคนเป็นนักดนตรี แต่ไม่ใช่นักดนตรีทุกคนที่เป็นนักไวโอลินหรือนักเปียโน นั่นหมายความว่าคุณสามารถใช้วิธีการเล่นของนักดนตรีได้หากไม่จำเป็นต้องสร้างใหม่ หรือคุณสามารถเรียกวิธีการของผู้ปกครองจากเด็กโดยใช้คำหลักsuper ลองทำในรหัสของนักเปียโน:
public class Pianist extends Musician {
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
}
ตอนนี้ขอเรียกเมธอดmain() ของเรา ในคลาสDemo นี่คือผลลัพธ์:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
วิธีการโอเวอร์โหลด
การโอเวอร์โหลดเมธอดหมายถึงการใช้เมธอดต่างๆ ที่มีชื่อเดียวกันในคลาสเดียวกัน โดยจะต้องแตกต่างกันในแง่ของจำนวน ลำดับ หรือประเภทของพารามิเตอร์ สมมติว่านักเปียโนสามารถเล่นเปียโนอะคูสติกและเปียโนไฟฟ้าได้ ในการเล่นไฟฟ้า นักดนตรีต้องการไฟฟ้า ลองสร้างplay() สอง วิธี ที่แตกต่างกัน ตัวแรกไม่มีพารามิเตอร์สำหรับเปียโนอะคูสติก และตัวที่สองมีพารามิเตอร์ที่ระบุว่ามีไฟฟ้าหรือไม่public class Pianist extends Musician {
String name;
int age;
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
System.out.println("I am playing the piano...");
}
else System.out.println("I can't play this without electricity.");
}
}
อย่างไรก็ตาม คุณสามารถใช้ เมธอด play() แรก ภายในเมธอดplay(บูลีน) ที่สอง ในลักษณะนี้:
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
play();
}
else System.out.println("I can't play this without electricity.");
}
มาเพิ่มบรรทัดใน คลาส สาธิต ของเรา เพื่อสาธิตการโอเวอร์โหลดของเรา:
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 23, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
System.out.println("The pianist will now try the electric piano:");
pianist.play(true);
System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
pianist.play(false);
}
}
นี่คือผลลัพธ์:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
Java รู้ว่าควรใช้เมธอดใดตามพารามิเตอร์และประเภทอ็อบเจกต์ นั่นคือความหลากหลาย
สิ่งที่เป็นนามธรรม
เมื่อเรากำหนดคลาส เรากำลังพยายามสร้างแบบจำลองของบางสิ่ง ตัวอย่างเช่น สมมติว่าเรากำลังเขียนวิดีโอเกมชื่อ MyRacer โดยมีรถแข่งหลายคัน ผู้เล่นสามารถเลือกหนึ่งในนั้นแล้วอัปเดตในภายหลังหรือซื้ออันอื่น ดังนั้น… รถคืออะไร? รถยนต์เป็นสิ่งที่ค่อนข้างซับซ้อน แต่ถ้าเรากำลังพยายามสร้างวิดีโอเกมแข่งรถ (แทนที่จะเป็นโปรแกรมจำลองการขับรถ) เราก็ไม่จำเป็นต้องอธิบายถึงเกียร์และปะเก็นนับพันที่มีอยู่ในนั้น เราต้องการรุ่น ความเร็วสูงสุด ลักษณะความคล่องแคล่ว ราคา สี… และนั่นอาจเพียงพอแล้ว นั่นคือรูปแบบของรถสำหรับเกมของเรา ต่อมาใน MyRacer 2 สมมติว่าเราตัดสินใจเพิ่มยางที่ส่งผลต่อการควบคุมรถบนท้องถนน นี่คือรูปแบบที่แตกต่างกันเพราะเราเพิ่มรายละเอียดเพิ่มเติม อนุญาต' s กำหนด data abstraction เป็นกระบวนการระบุเฉพาะลักษณะที่สำคัญ (หรือจำเป็น) ของวัตถุและละเว้นรายละเอียดที่ไม่เกี่ยวข้องใดๆ นามธรรมมีหลายระดับ ตัวอย่างเช่น หากคุณเป็นผู้โดยสารบนรถบัส คุณต้องรู้ว่ารถบัสของคุณมีลักษณะอย่างไรและกำลังจะไปที่ไหน แต่คุณไม่จำเป็นต้องรู้วิธีการขับ หากคุณเป็นคนขับรถบัส คุณไม่จำเป็นต้องรู้วิธีสร้างรถบัสใหม่ — คุณต้องรู้วิธีขับเท่านั้น แต่ถ้าคุณเป็นผู้ผลิตรถบัส คุณต้องไปที่ระดับล่างของสิ่งที่เป็นนามธรรม เพราะรายละเอียดของการออกแบบรถบัสมีความสำคัญต่อคุณมาก ฉันหวังว่าคุณจะเข้าใจสิ่งที่ฉันหมายถึง คุณจำเป็นต้องรู้ว่ารถบัสของคุณมีลักษณะอย่างไรและกำลังจะไปที่ไหน แต่คุณไม่จำเป็นต้องรู้วิธีการขับ หากคุณเป็นคนขับรถบัส คุณไม่จำเป็นต้องรู้วิธีสร้างรถบัสใหม่ — คุณต้องรู้วิธีขับเท่านั้น แต่ถ้าคุณเป็นผู้ผลิตรถบัส คุณต้องไปที่ระดับล่างของสิ่งที่เป็นนามธรรม เพราะรายละเอียดของการออกแบบรถบัสมีความสำคัญต่อคุณมาก ฉันหวังว่าคุณจะเข้าใจสิ่งที่ฉันหมายถึง คุณจำเป็นต้องรู้ว่ารถบัสของคุณมีลักษณะอย่างไรและกำลังจะไปที่ไหน แต่คุณไม่จำเป็นต้องรู้วิธีการขับ หากคุณเป็นคนขับรถบัส คุณไม่จำเป็นต้องรู้วิธีสร้างรถบัสใหม่ — คุณต้องรู้วิธีขับเท่านั้น แต่ถ้าคุณเป็นผู้ผลิตรถบัส คุณต้องไปที่ระดับล่างของสิ่งที่เป็นนามธรรม เพราะรายละเอียดของการออกแบบรถบัสมีความสำคัญต่อคุณมาก ฉันหวังว่าคุณจะเข้าใจสิ่งที่ฉันหมายถึงมันทำงานอย่างไรใน Java:
มาสร้างนามธรรมสี่ระดับใน Java หรือมากกว่าใน OOP — จากระดับต่ำสุด (เฉพาะเจาะจงที่สุด) ไปจนถึงระดับสูงสุด (นามธรรมที่สุด)-
นามธรรมระดับต่ำสุดคือวัตถุเฉพาะ เป็นเอนทิตีที่มีชุดของคุณลักษณะที่เป็นของคลาสเฉพาะ มีค่าฟิลด์เฉพาะ
-
เทมเพลตสำหรับสร้างวัตถุคือคลาส เป็นคำอธิบายชุดของวัตถุที่มีคุณสมบัติและโครงสร้างภายในคล้ายคลึงกัน
-
คลาสนามธรรมเป็นคำอธิบายนามธรรมของคุณลักษณะของชุดคลาส (ทำหน้าที่เป็นแม่แบบสำหรับการสืบทอดโดยคลาสอื่น) มันมีความเป็นนามธรรมในระดับสูง ดังนั้นจึงเป็นไปไม่ได้ที่จะสร้างวัตถุโดยตรงจากคลาสนามธรรม คลาสลูกของคลาสนามธรรมเท่านั้นที่สามารถใช้สร้างวัตถุได้ คลาสนามธรรมอาจรวมเมธอดด้วยการนำไปใช้งาน แต่นี่ไม่ใช่ข้อกำหนด
-
อินเทอร์เฟซคือโครงสร้างของภาษาการเขียนโปรแกรม Java ที่มีเฉพาะวิธีการสาธารณะแบบนามธรรมและฟิลด์ค่าคงที่แบบคงที่ (แบบคงที่สุดท้าย) กล่าวอีกนัยหนึ่งไม่สามารถใช้คลาสนามธรรมหรืออินเทอร์เฟซเพื่อสร้างวัตถุได้
ตัวอย่างอินเทอร์เฟซในโค้ด Java
interface Human {
public void struggle();
public void protect();
}
interface Vulcan {
int angleOfPointyEars;
public void turnOffEmotions(boolean isOn);
public void telepathy();
}
คุณสามารถใช้มากกว่าหนึ่งอินเทอร์เฟซ
The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
public void protect() {
System.out.println("You are under my protection!”);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
public void telepathy() {
System.out.println("Connecting to your brain...");
}
}
สำหรับนักเรียนระดับเริ่มต้น ซึ่งครอบคลุมแนวคิดหลักทั้งหมดของการเขียนโปรแกรมเชิงวัตถุในภาษาจาวา นอกจากหลักการ OOP หลัก 4 ข้อแล้ว Java ยังมีการเชื่อมโยง การรวม และองค์ประกอบ คุณสามารถเรียกพวกเขาว่า "หลักการ OOP เพิ่มเติม" พวกเขาสมควรได้รับบทความแยกต่างหาก