แม้ว่าความแตกต่างได้อธิบายไว้แล้วในรายละเอียดที่ดีในโพสต์นี้ แต่ฉันอยากจะเน้นว่าทำไมส่วนหนึ่งของมัน
ทำไมความแตกต่างจึงมีความสำคัญในภาษา OOP
ลองสร้างแอปพลิเคชั่นที่เรียบง่ายสำหรับทีวีที่มีและไม่มีมรดก / ความหลากหลาย โพสต์แอปพลิเคชั่นแต่ละรุ่นเราทำย้อนหลังเล็กน้อย
สมมติว่าคุณเป็นวิศวกรซอฟต์แวร์ที่ บริษัท ทีวีและขอให้คุณเขียนซอฟต์แวร์สำหรับตัวควบคุมระดับเสียง, ความสว่างและสีเพื่อเพิ่มและลดค่าของพวกเขาในคำสั่งผู้ใช้
คุณเริ่มต้นด้วยการเขียนคลาสสำหรับแต่ละคุณสมบัติเหล่านี้โดยการเพิ่ม
- set: - เพื่อตั้งค่าของตัวควบคุม (หากมีรหัสเฉพาะของตัวควบคุม)
- รับ: - เพื่อรับค่าของตัวควบคุม (หากมีรหัสเฉพาะตัวควบคุม)
- Adjust: - เพื่อตรวจสอบอินพุตและการตั้งค่าคอนโทรลเลอร์ (การตรวจสอบทั่วไป .. เป็นอิสระจากคอนโทรลเลอร์)
- การแมปอินพุตของผู้ใช้กับตัวควบคุม: - เพื่อรับอินพุตของผู้ใช้และเรียกใช้ตัวควบคุมตามลำดับ
แอปพลิเคชันเวอร์ชัน 1
import java.util.Scanner;
class VolumeControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class BrightnessControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ColourControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
/*
* There can be n number of controllers
* */
public class TvApplicationV1 {
public static void main(String[] args) {
VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
ColourControllerV1 colourControllerV1 = new ColourControllerV1();
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println("Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV1.adjust(5);
break;
}
case 2: {
volumeControllerV1.adjust(-5);
break;
}
case 3: {
brightnessControllerV1.adjust(5);
break;
}
case 4: {
brightnessControllerV1.adjust(-5);
break;
}
case 5: {
colourControllerV1.adjust(5);
break;
}
case 6: {
colourControllerV1.adjust(-5);
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
ตอนนี้คุณมีแอปพลิเคชันการทำงานรุ่นแรกของเราพร้อมที่จะนำไปใช้งานแล้ว ถึงเวลาวิเคราะห์งานที่ทำไปแล้ว
ปัญหาในแอปพลิเคชันทีวีเวอร์ชัน 1
- รหัสการปรับ (ค่า int) ซ้ำกันในทั้งสามคลาส คุณต้องการลดความซ้ำซ้อนของรหัส (แต่คุณไม่ได้คิดว่ารหัสทั่วไปและย้ายไปที่บางระดับชั้นเพื่อหลีกเลี่ยงรหัสที่ซ้ำกัน)
คุณตัดสินใจที่จะอยู่กับมันตราบใดที่ใบสมัครของคุณทำงานตามที่คาดไว้
หลังจากนั้นบางครั้งบอสของคุณจะกลับมาหาคุณและขอให้คุณเพิ่มฟังก์ชั่นการรีเซ็ตให้กับแอปพลิเคชันที่มีอยู่ การรีเซ็ตจะตั้งค่าตัวควบคุมทั้งสามทั้งสามเป็นค่าเริ่มต้นที่เกี่ยวข้อง
คุณเริ่มเขียนคลาสใหม่ (ResetFunctionV2) สำหรับฟังก์ชันการทำงานใหม่และแมปรหัสการแมปการป้อนข้อมูลผู้ใช้สำหรับคุณลักษณะใหม่นี้
แอปพลิเคชันเวอร์ชัน 2
import java.util.Scanner;
class VolumeControllerV2 {
private int defaultValue = 25;
private int value;
int getDefaultValue() {
return defaultValue;
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class BrightnessControllerV2 {
private int defaultValue = 50;
private int value;
int get() {
return value;
}
int getDefaultValue() {
return defaultValue;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ColourControllerV2 {
private int defaultValue = 40;
private int value;
int get() {
return value;
}
int getDefaultValue() {
return defaultValue;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ResetFunctionV2 {
private VolumeControllerV2 volumeControllerV2 ;
private BrightnessControllerV2 brightnessControllerV2;
private ColourControllerV2 colourControllerV2;
ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2) {
this.volumeControllerV2 = volumeControllerV2;
this.brightnessControllerV2 = brightnessControllerV2;
this.colourControllerV2 = colourControllerV2;
}
void onReset() {
volumeControllerV2.set(volumeControllerV2.getDefaultValue());
brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
colourControllerV2.set(colourControllerV2.getDefaultValue());
}
}
/*
* so on
* There can be n number of controllers
*
* */
public class TvApplicationV2 {
public static void main(String[] args) {
VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
ColourControllerV2 colourControllerV2 = new ColourControllerV2();
ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV2.adjust(5);
break;
}
case 2: {
volumeControllerV2.adjust(-5);
break;
}
case 3: {
brightnessControllerV2.adjust(5);
break;
}
case 4: {
brightnessControllerV2.adjust(-5);
break;
}
case 5: {
colourControllerV2.adjust(5);
break;
}
case 6: {
colourControllerV2.adjust(-5);
break;
}
case 7: {
resetFunctionV2.onReset();
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
เพื่อให้คุณพร้อมใช้งานกับคุณสมบัติรีเซ็ต แต่ตอนนี้คุณเริ่มตระหนักว่า
ปัญหาในแอปพลิเคชันทีวีเวอร์ชัน 2
- หากมีการแนะนำคอนโทรลเลอร์ใหม่ให้กับผลิตภัณฑ์คุณจะต้องเปลี่ยนรหัสคุณสมบัติรีเซ็ต
- หากจำนวนตัวควบคุมเพิ่มขึ้นสูงมากคุณจะมีปัญหาในการเก็บข้อมูลอ้างอิงของตัวควบคุม
- รีเซ็ตรหัสคุณลักษณะควบคู่ไปกับรหัสของคลาสคอนโทรลเลอร์อย่างแน่นหนา (เพื่อรับและตั้งค่าเริ่มต้น)
- รีเซ็ตฟีเจอร์คลาส (ResetFunctionV2) สามารถเข้าถึงวิธีอื่นของ (ปรับ) คลาสคอนโทรลเลอร์ที่ไม่พึงประสงค์
ในเวลาเดียวกันคุณได้ยินจากคุณบอสว่าคุณอาจต้องเพิ่มคุณสมบัติที่คอนโทรลเลอร์แต่ละตัวเริ่มต้นต้องตรวจสอบไดรเวอร์รุ่นล่าสุดจากที่เก็บโฮสต์ไดรเวอร์ของ บริษัท ผ่านอินเทอร์เน็ต
ตอนนี้คุณเริ่มคิดว่าคุณสมบัติใหม่นี้ที่จะเพิ่มคล้ายกับคุณสมบัติการตั้งค่าใหม่และปัญหาของแอปพลิเคชัน (V2) จะทวีคูณถ้าคุณไม่คำนึงถึงแอปพลิเคชันของคุณอีกครั้ง
คุณเริ่มคิดถึงการใช้การสืบทอดเพื่อให้คุณสามารถใช้ประโยชน์จากความสามารถ polymorphic ของ JAVA และคุณเพิ่มคลาส abstract ใหม่ (ControllerV3) ไปยัง
- ประกาศลายเซ็นของ get และ set method
- มีการปรับใช้งานวิธีการซึ่งถูกจำลองแบบก่อนหน้านี้ในตัวควบคุมทั้งหมด
- ประกาศเมธอด setDefault เพื่อให้คุณลักษณะรีเซ็ตสามารถนำไปใช้ประโยชน์ได้อย่างง่ายดายจาก Polymorphism
ด้วยการปรับปรุงเหล่านี้คุณมีแอปพลิเคชั่นทีวีเวอร์ชัน 3 พร้อมกับคุณ
แอปพลิเคชันเวอร์ชัน 3
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
abstract class ControllerV3 {
abstract void set(int value);
abstract int get();
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3 {
private int defaultValue = 25;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
}
class BrightnessControllerV3 extends ControllerV3 {
private int defaultValue = 50;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
}
class ColourControllerV3 extends ControllerV3 {
private int defaultValue = 40;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
}
class ResetFunctionV3 {
private List<ControllerV3> controllers = null;
ResetFunctionV3(List<ControllerV3> controllers) {
this.controllers = controllers;
}
void onReset() {
for (ControllerV3 controllerV3 :this.controllers) {
controllerV3.setDefault();
}
}
}
/*
* so on
* There can be n number of controllers
*
* */
public class TvApplicationV3 {
public static void main(String[] args) {
VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
ColourControllerV3 colourControllerV3 = new ColourControllerV3();
List<ControllerV3> controllerV3s = new ArrayList<>();
controllerV3s.add(volumeControllerV3);
controllerV3s.add(brightnessControllerV3);
controllerV3s.add(colourControllerV3);
ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV3.adjust(5);
break;
}
case 2: {
volumeControllerV3.adjust(-5);
break;
}
case 3: {
brightnessControllerV3.adjust(5);
break;
}
case 4: {
brightnessControllerV3.adjust(-5);
break;
}
case 5: {
colourControllerV3.adjust(5);
break;
}
case 6: {
colourControllerV3.adjust(-5);
break;
}
case 7: {
resetFunctionV3.onReset();
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
แม้ว่าส่วนใหญ่ของปัญหาที่ระบุไว้ในรายการปัญหาของ V2 ได้รับการแก้ไขยกเว้น
ปัญหาในแอปพลิเคชันทีวีเวอร์ชัน 3
- รีเซ็ตฟีเจอร์คลาส (ResetFunctionV3) สามารถเข้าถึงวิธีอื่นของ (ปรับ) คลาสคอนโทรลเลอร์ที่ไม่พึงประสงค์
อีกครั้งคุณคิดว่าจะแก้ปัญหานี้เพราะตอนนี้คุณมีคุณสมบัติอื่น (อัปเดตไดรเวอร์เมื่อเริ่มต้น) เพื่อนำไปใช้เช่นกัน หากคุณไม่แก้ไขจะได้รับการจำลองแบบไปยังคุณสมบัติใหม่เช่นกัน
ดังนั้นคุณแบ่งสัญญาที่กำหนดไว้ในคลาสนามธรรมและเขียน 2 อินเตอร์เฟสสำหรับ
- รีเซ็ตคุณสมบัติ
- อัพเดตไดร์เวอร์
และให้ชั้นรูปธรรมที่ 1 ของคุณนำไปใช้งานได้ดังนี้
แอปพลิเคชันเวอร์ชัน 4
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
interface OnReset {
void setDefault();
}
interface OnStart {
void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
abstract void set(int value);
abstract int get();
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class VolumeControllerV4 extends ControllerV4 {
private int defaultValue = 25;
private int value;
@Override
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
@Override
public void setDefault() {
set(defaultValue);
}
@Override
public void checkForDriverUpdate() {
System.out.println("Checking driver update for VolumeController .... Done");
}
}
class BrightnessControllerV4 extends ControllerV4 {
private int defaultValue = 50;
private int value;
@Override
int get() {
return value;
}
@Override
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
@Override
public void setDefault() {
set(defaultValue);
}
@Override
public void checkForDriverUpdate() {
System.out.println("Checking driver update for BrightnessController .... Done");
}
}
class ColourControllerV4 extends ControllerV4 {
private int defaultValue = 40;
private int value;
@Override
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
@Override
public void setDefault() {
set(defaultValue);
}
@Override
public void checkForDriverUpdate() {
System.out.println("Checking driver update for ColourController .... Done");
}
}
class ResetFunctionV4 {
private List<OnReset> controllers = null;
ResetFunctionV4(List<OnReset> controllers) {
this.controllers = controllers;
}
void onReset() {
for (OnReset onreset :this.controllers) {
onreset.setDefault();
}
}
}
class InitializeDeviceV4 {
private List<OnStart> controllers = null;
InitializeDeviceV4(List<OnStart> controllers) {
this.controllers = controllers;
}
void initialize() {
for (OnStart onStart :this.controllers) {
onStart.checkForDriverUpdate();
}
}
}
/*
* so on
* There can be n number of controllers
*
* */
public class TvApplicationV4 {
public static void main(String[] args) {
VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
ColourControllerV4 colourControllerV4 = new ColourControllerV4();
List<ControllerV4> controllerV4s = new ArrayList<>();
controllerV4s.add(brightnessControllerV4);
controllerV4s.add(volumeControllerV4);
controllerV4s.add(colourControllerV4);
List<OnStart> controllersToInitialize = new ArrayList<>();
controllersToInitialize.addAll(controllerV4s);
InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
initializeDeviceV4.initialize();
List<OnReset> controllersToReset = new ArrayList<>();
controllersToReset.addAll(controllerV4s);
ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV4.adjust(5);
break;
}
case 2: {
volumeControllerV4.adjust(-5);
break;
}
case 3: {
brightnessControllerV4.adjust(5);
break;
}
case 4: {
brightnessControllerV4.adjust(-5);
break;
}
case 5: {
colourControllerV4.adjust(5);
break;
}
case 6: {
colourControllerV4.adjust(-5);
break;
}
case 7: {
resetFunctionV4.onReset();
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
ตอนนี้ปัญหาทั้งหมดที่คุณได้รับการแก้ไขแล้วและคุณก็ตระหนักว่าด้วยการใช้การสืบทอดและความหลากหลายที่คุณสามารถทำได้
- เก็บส่วนต่าง ๆ ของแอปพลิเคชันไว้อย่างหลวม ๆ (องค์ประกอบของฟีเจอร์การรีเซ็ตหรือการอัปเดตไดรเวอร์ไม่จำเป็นต้องทราบถึงคลาสคอนโทรลเลอร์จริง (ระดับเสียง, ความสว่างและสี), การใช้คลาส OnReset หรือ OnStart จะยอมรับคุณสมบัติการรีเซ็ตหรือไดรเวอร์ ส่วนประกอบตามลำดับ)
- การเพิ่มประสิทธิภาพของแอพพลิเคชั่นจะง่ายขึ้น (การเพิ่มตัวควบคุมใหม่จะไม่ส่งผลกระทบต่อการรีเซ็ตหรือองค์ประกอบคุณสมบัติการอัพเดทไดรเวอร์และตอนนี้มันง่ายสำหรับคุณที่จะเพิ่มใหม่)
- เก็บเลเยอร์ของสิ่งที่เป็นนามธรรม (ขณะนี้คุณลักษณะรีเซ็ตสามารถดูได้เฉพาะเมธอด setDefault ของตัวควบคุมและคุณลักษณะรีเซ็ตสามารถดูได้เฉพาะวิธี checkForDriverUpdate ของคอนโทรลเลอร์
หวังว่านี่จะช่วย :-)