Java 學習記錄 32 — Composition

張小雄
4 min readJan 30, 2021

--

Composition 解決了 Inheritance 只能一個的問題

電腦是由各種部件組裝起來,像是:螢幕、機殼、主機板

這三個部件的裡面又有各種小部件

那最後電腦這個 Class 要怎麼寫

如果用 Inheritance 就很難達成

Composition 就是為了解決此問題

創四個主要的 Class (電腦、螢幕、機殼、主機板)和一些小部件的 Class 來了解 Composition 使用情境

Motherboard.java

public class Motherboard {    private String model;
private String manufacturer;
private String bios;
private int ramSlots;
private int cardSlots;
public Motherboard(String model, String manufacturer, String bios, int ramSlots, int cardSlots) {
this.model = model;
this.manufacturer = manufacturer;
this.bios = bios;
this.ramSlots = ramSlots;
this.cardSlots = cardSlots;
}
public void loadProgram(String programName){
System.out.println("Program " + programName + " is now loading..." );
}
public String getModel() {
return model;
}
public String getManufacturer() {
return manufacturer;
}
public String getBios() {
return bios;
}
public int getRamSlots() {
return ramSlots;
}
public int getCardSlots() {
return cardSlots;
}
}

monitor.java

public class Monitor {
private String model;
private String manufacturer;
private int size;
private Resolution nativeResolution;
public Monitor(String model, String manufacturer, int size, Resolution nativeResolution) {
this.model = model;
this.manufacturer = manufacturer;
this.size = size;
this.nativeResolution = nativeResolution;
}
public void drawPixelAt(int x, int y, String color){
System.out.println("Drawing pixel at " + x + "," + y + " in color " + color);
}
public String getModel() {
return model;
}
public String getManufacturer() {
return manufacturer;
}
public int getSize() {
return size;
}
public Resolution getNativeResolution() {
return nativeResolution;
}
}

可以看到第4個 field 是一個 Resolution Class

此時還沒寫到,下一個會寫

但這就是 composition

需要的時候可以透過 monitor 來調用 resolution 的 filed 跟 method

後面會展示

resolution.java

public class Resolution {
private int width;
private int height;
public Resolution(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}

case.java

public class Case {
private String model;
private String manufacturer;
private String powerSupply;
private Dimensions dimensions;
public Case(String model, String manufacturer, String powerSupply, Dimensions dimensions) {
this.model = model;
this.manufacturer = manufacturer;
this.powerSupply = powerSupply;
this.dimensions = dimensions;
}
public void pressPowerButton(){
System.out.println("Power button was pressed");
}
public String getModel() {
return model;
}
public String getManufacturer() {
return manufacturer;
}
public String getPowerSupply() {
return powerSupply;
}
public Dimensions getDimensions() {
return dimensions;
}
}

第 4 個 field 也是 Class

dimension.java

public class Dimensions {
private int width;
private int height;
private int depth;
public Dimensions(int width, int height, int depth) {
this.width = width;
this.height = height;
this.depth = depth;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getDepth() {
return depth;
}
}

computer.java

public class Computer {
private Case theCase;
private Monitor monitor;
private Motherboard motherboard;
public Computer(Case theCase, Monitor monitor, Motherboard motherboard) {
this.theCase = theCase;
this.monitor = monitor;
this.motherboard = motherboard;
}
public Case getTheCase() {
return theCase;
}
public Monitor getMonitor() {
return monitor;
}
public Motherboard getMotherboard() {
return motherboard;
}
}

main.java

public class main {    public static void main(String[] args) {
Case theCase = new Case("Tx650","Lian Li", "Gold", new Dimensions(120,50,80));
Monitor theMonitor = new Monitor("Corporation 24", "BenQ", 17, new Resolution(1920, 1080));
Motherboard theMotherboard = new Motherboard("M32", "ASUS", "ASUS", 4, 8);
Computer mine_computer = new Computer(theCase, theMonitor, theMotherboard);
mine_computer.getTheCase().pressPowerButton();
mine_computer.getMotherboard().loadProgram("Super Mario");
mine_computer.getMonitor().drawPixelAt(720, 480, "yellow");
}
}

參數用到 Class 時,是可以直接在參數寫入 new Class

所以 new Computer(也可以在參數直接 new 3 個 Class)

只是這樣的話會看起來太擠,為了可讀性還是拆開來。

輸出結果:

Power button was pressed

Program Super Mario is now loading…

Drawing pixel at 720,480 in color yellow

這邊5個 Class

沒有用到任何 Inheritance

但還是成功調用了不同 Class 中的 method

這邊的 getTheCase() 就等於直接調用了 new 出來的 case

在 Computer 中的 filed 就是如此設定 private Case theCase;

而 get 返回的也是此 field

其他兩個 get 也是如此

Saurav 同學解釋了 Composition 跟 Inheritance 的差異

Composition follows HAS-A relationship

Inheritance follows IS-A relationship

For example:-

Bathroom HAS-A Tub — — — — — — — — — — → Composition

Dog IS-A Animal — — — — — — — — — — — — → Inheritance

You cannot say Bathroom IS-A Tub, it simply doesn’t make sense, hence when we have HAS-A relationship, we use Composition.

Similarly, Dog IS-A animal, Dog HAS-A animal makes no sense.

優化

computer.java

public class Computer {
private Case theCase;
private Monitor monitor;
private Motherboard motherboard;
public Computer(Case theCase, Monitor monitor, Motherboard motherboard) {
this.theCase = theCase;
this.monitor = monitor;
this.motherboard = motherboard;
}
public void powerUp(){
theCase.pressPowerButton();
System.out.println("Power of computer is up now.");
}
public void showProgram(String programName){
motherboard.loadProgram(programName);
monitor.drawPixelAt(1080,720,"Black background");
System.out.println("Window of program is opened.");
}
}

刪除了 3個 get

直接在 method 裡面調用 field(Class)

main.java

mine_computer.powerUp();
mine_computer.showProgram("Super Mario");

輸出結果:

Power button was pressed

Power of computer is up now.

Program Super Mario is now loading…

Drawing pixel at 1080,720 in color Black background

Window of program is opened.

小挑戰:

Create a single room of a house using composition.

Think about the things that should be included in the room.

Maybe physical parts of the house but furniture as well

Add at least one method to access an object via a getter and

then that objects public method as you saw in the previous video

then add at least one method to hide the object e.g. not using a getter

but to access the object used in composition within the main class

like you saw in this video.

此題為自由發揮

我寫的放在本篇使用代碼中的 room

main 換題目我就清代碼留一個紀錄

main.java

public class main {    public static void main(String[] args) {
Door theDoor = new Door("Wood");
Bed theBed = new Bed(2, "King");
BookCase theBookCase = new BookCase();
Room theRoom = new Room(theDoor, theBed, theBookCase);
theRoom.close_door();
theRoom.getTheDoor().lock_door();
theRoom.putBook("Red hat girl");
theRoom.putBook("Black hat boy");
theRoom.getTheBookCase().checkBook();
theRoom.getTheBed().getPillowNumber();
theRoom.getTheBed().getComfortersSize();
theRoom.open_door();
}
}

輸出結果:

The door is close.

The door is lock now.

Bookcase has: Red hat girl . Black hat boy .

Pillow has 2

Comforters size is King

The door is open.

--

--

張小雄
張小雄

Written by 張小雄

記錄成為軟體工程師的過程

No responses yet