Mặc dù, Đa hình đã được giải thích rất chi tiết trong bài viết này nhưng tôi muốn nhấn mạnh hơn vào lý do tại sao một phần của nó.
Tại sao đa hình rất quan trọng trong bất kỳ ngôn ngữ OOP nào.
Chúng ta hãy thử xây dựng một ứng dụng đơn giản cho TV có và không có Kế thừa / Đa hình. Đăng từng phiên bản của ứng dụng, chúng tôi làm một hồi tưởng nhỏ.
Giả sử, bạn là một kỹ sư phần mềm tại một công ty TV và bạn được yêu cầu viết phần mềm cho bộ điều khiển Âm lượng, Độ sáng và Màu sắc để tăng và giảm giá trị của chúng theo lệnh người dùng.
Bạn bắt đầu với các lớp viết cho mỗi tính năng này bằng cách thêm
- set: - Để đặt giá trị của bộ điều khiển. (Giả sử điều này có mã cụ thể của bộ điều khiển)
- get: - Để lấy giá trị của bộ điều khiển. (Giả sử điều này có mã cụ thể của bộ điều khiển)
- điều chỉnh: - Để xác thực đầu vào và đặt bộ điều khiển. (Xác thực chung .. độc lập với bộ điều khiển)
- ánh xạ đầu vào của người dùng với các bộ điều khiển: - Để có được đầu vào của người dùng và gọi các bộ điều khiển phù hợp.
Phiên bản ứng dụng 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;
}
}
}
}
Bây giờ bạn đã có phiên bản đầu tiên của ứng dụng làm việc của chúng tôi sẵn sàng để được triển khai. Thời gian để phân tích công việc được thực hiện cho đến nay.
Các sự cố trong Ứng dụng TV Phiên bản 1
- Mã điều chỉnh (int value) được nhân đôi trong cả ba lớp. Bạn muốn giảm thiểu sự trùng lặp mã. (Nhưng bạn đã không nghĩ về mã phổ biến và chuyển nó sang một số siêu hạng để tránh mã trùng lặp)
Bạn quyết định sống với điều đó miễn là ứng dụng của bạn hoạt động như mong đợi.
Sau đó, ông chủ của bạn quay lại với bạn và yêu cầu bạn thêm chức năng đặt lại vào ứng dụng hiện có. Đặt lại sẽ đặt cả 3 ba bộ điều khiển về giá trị mặc định tương ứng của chúng.
Bạn bắt đầu viết một lớp mới (ResetFunctionV2) cho chức năng mới và ánh xạ mã ánh xạ đầu vào của người dùng cho tính năng mới này.
Phiên bản ứng dụng 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;
}
}
}
}
Vậy là bạn đã sẵn sàng cho ứng dụng của mình với tính năng Reset. Nhưng, bây giờ bạn bắt đầu nhận ra rằng
Các sự cố trong Ứng dụng TV Phiên bản 2
- Nếu bộ điều khiển mới được giới thiệu cho sản phẩm, bạn phải thay đổi mã tính năng Đặt lại.
- Nếu số lượng bộ điều khiển tăng rất cao, bạn sẽ gặp vấn đề trong việc giữ các tham chiếu của bộ điều khiển.
- Đặt lại mã tính năng được kết hợp chặt chẽ với tất cả mã của Bộ điều khiển (để lấy và đặt giá trị mặc định).
- Đặt lại lớp tính năng (ResetFunctionV2) có thể truy cập phương thức khác của lớp Điều khiển (điều chỉnh) không mong muốn.
Đồng thời, bạn nghe được từ ông chủ của mình rằng bạn có thể phải thêm một tính năng trong đó mỗi bộ điều khiển, khi khởi động, cần kiểm tra phiên bản trình điều khiển mới nhất từ kho lưu trữ trình điều khiển được lưu trữ của công ty qua internet.
Bây giờ bạn bắt đầu nghĩ rằng tính năng mới này sẽ được thêm giống với tính năng Đặt lại và Vấn đề về Ứng dụng (V2) sẽ được nhân lên nếu bạn không tính lại ứng dụng của mình.
Bạn bắt đầu nghĩ đến việc sử dụng tính kế thừa để bạn có thể tận dụng khả năng đa hình của JAVA và bạn thêm một lớp trừu tượng mới (ControllerV3) vào
- Khai báo chữ ký của phương thức get và set.
- Chứa điều chỉnh phương thức thực hiện đã được sao chép trước đó trong số tất cả các bộ điều khiển.
- Khai báo phương thức setDefault để tính năng đặt lại có thể dễ dàng thực hiện bằng cách sử dụng Đa hình.
Với những cải tiến này, bạn đã có sẵn phiên bản 3 của ứng dụng TV.
Phiên bản ứng dụng 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;
}
}
}
}
Mặc dù hầu hết các vấn đề được liệt kê trong danh sách vấn đề của V2 đã được giải quyết ngoại trừ
Các sự cố trong Ứng dụng TV Phiên bản 3
- Đặt lại lớp tính năng (ResetFunctionV3) có thể truy cập phương thức khác của lớp Điều khiển (điều chỉnh) không mong muốn.
Một lần nữa, bạn nghĩ đến việc giải quyết vấn đề này, vì bây giờ bạn có một tính năng khác (cập nhật trình điều khiển khi khởi động) để thực hiện. Nếu bạn không sửa nó, nó cũng sẽ được nhân rộng sang các tính năng mới.
Vì vậy, bạn chia hợp đồng được xác định trong lớp trừu tượng và viết 2 giao diện cho
- Đặt lại tính năng.
- Cập nhật trình điều khiển.
Và có lớp bê tông đầu tiên của bạn thực hiện chúng như dưới đây
Phiên bản ứng dụng 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;
}
}
}
}
Bây giờ tất cả các vấn đề mà bạn phải đối mặt đã được giải quyết và bạn nhận ra rằng với việc sử dụng Kế thừa và Đa hình, bạn có thể
- Giữ các phần khác nhau của ứng dụng được ghép lỏng lẻo (Các thành phần tính năng Đặt lại hoặc Cập nhật Trình điều khiển không cần phải biết về các lớp trình điều khiển thực tế (Âm lượng, Độ sáng và Màu sắc), mọi lớp triển khai OnReset hoặc OnStart đều được chấp nhận để tính năng Đặt lại hoặc Cập nhật trình điều khiển thành phần tương ứng).
- Việc cải tiến ứng dụng trở nên dễ dàng hơn (Bổ sung bộ điều khiển mới sẽ không ảnh hưởng đến việc thiết lập lại thành phần tính năng cập nhật trình điều khiển và giờ đây thật dễ dàng để bạn thêm những cái mới)
- Giữ lớp trừu tượng. (Bây giờ tính năng Đặt lại chỉ có thể thấy phương thức setDefault của bộ điều khiển và tính năng Đặt lại chỉ có thể thấy phương thức bộ điều khiển checkForDriverUpdate)
Hi vọng điêu nay co ich :-)