# 物件導向軟體工程 歷屆考古

# 期中考


# 110

# Q1

Q: 違反 SOLID 哪個原則
A: 違反 OCP 重點在 Graphic Editor 裡面我可以看出我們會根據 shape 型別用 if else 去判斷那當我們今天有新型別 Triangle 會需要須改 Main code GraphicEditor

# Q2

Q: 看結果
A: 首先我們看到 Coffee 是該題 Decorator 與真正 Coffee Expresso (濃縮咖啡) 的共同介面,這題實在是太明顯了一看就知道是 Decorator Pattern,

那我們看 Main Code 他有 printCoffee 方法會印出該 Coffee 的 Description 與 Price (描述與價格)

第一段 New Expresso 我們可以從 Expresso 的描述看到 他的 Desciption 是 Expresso 與價格 (cost) 是 60 元 因此第一個結果為 Cost:60.0,Desciption Espresso

第二段 我們 New 出 WithMilk 且將前一步驟的 Expresso 當成參數放進去,那這個被套用 Decorator 的結果為原有 Expresso 的 60.0+WithMilk 的 20.0 結果為 80.0 元,描述為 Expresso 的 Express+Milk

第三段與第四段 New 出 WithSugar 且將前一步的 Expresso 當成參數放進去,那這個被套用 Decorator 的結果為原有 Expresso 的 80.0+WithSugar 的 5.0 (兩次) 結果為 90.0 元,描述為 Expresso 的 Express+Milk +Sugar +Sugar

# Q3

Q: Print 結果?

A: 由題目可知是 Singleton Pattern ,MakeACaptain 有自己型別的 porperty 且 Constructor 為 Private 我們只能透過 getCaptain 方法取得 instance (captain) 也就是自己的 static property, 那看起來我們不管叫了幾次 getCaptain 都是回傳同一個物件。

我們看 MainCode
首先第一個 print 會印出 Trying to making a captain for your team

前面兩個 c1 c2 都是透過 getCaptain 來取得物件的 那前面 singleton Pattern 解釋過不論呼叫幾次都是回傳相同的物件 instance 那 c1 再被建立的時候會 print
Number of Instance 1
New captain is elected for your team

c2 則是
Otherwise , you already have a captain for your team

接者印出
Trying to make another captain for your team

c3 由於理由同上 那結果會跟 c2 相同印出

Otherwise , you already have a captain for your team

c1 與 c2 為相同物件 則印出
c1 and c2 are same instance

# Q4

Q1: trade off 取決
A1: 我可以知道 Composite 有 safe (安全) 與 transparent (透明) 方法
差別在於 leaf and composite 共同的 Interface Component 是否訂定了 Composite 的方法 (addComponent,removeComponent), 使用 transparent 會訂製在 interface 且由於需要 override 的關係,leaf class 也需要實作 addComponent removeComponent 這時只需要 throw exception or doNothing 就好

而 safe 方式是制定在 composite class 自己實作,這樣一來 leaf 就不需要去實作 addComponent removeComponent 方法可以達到 client code 不做沒意義的事情比如 在 leaf 呼叫 addComponent 但 由於不透明且 Client 是透過 Componet Interface 去了解所有物件的操作但 Composite class 是額外制定的 addComponent removeComponent 方法因此操作會被隱藏起來。

因此選擇透明是 Composite 的主要意圖

Q2: same manner explaination
A2: Composite Pattern 的主要意圖是對待所有物件統一化,因此讓所有 class 不同 composite or leaf 都去實作相同介面 (做同一種事情)

Q3: TextEditor
A3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
interface Glyph{
void addComponent(Glyph g);
void removeComponent(Glyph g);
void draw(Glyph g);
List<Glyph> getChild();
}

class Text implements Glyph{
void addComponent(Glyph g){
throw Exception();
}
void removeComponent(Glyph g){
throw Exception();
}
void draw(Glyph g){
drawSomthing;
}
List<Glyph> getChild(){
throw Exception();
}
}
class Graphic implements Glyph{
List<Glyph> glyphList = new ArrayList();
void addComponent(Glyph g){
this.glyphList.add(g);
}
void removeComponent(Glyph g){
this.glyphList.remove(g);
}
void draw(Glyph g){
for(Glyph g : glyphList){
g.draw();
}
}
List<Glyph> getChild(){
return glyphList;
}
}

# Q5

Q: 比較 Strategy 上下差異與寫 Code
A: Strategy Pattern 可以有兩種實作方式

  1. 先 new Context 再 new ConcreteStrategy 且放置進 Context 物件內 (圖一)
  2. 先 new ConcreteStrategy 再 new Context 且將 Context 放置入 ConcreteStrategy 內 (圖二)

# 109 Quiz1

# Q1

Q1: make method completeCourse() Unchangable 讓這個方法無法更改
A1: 在宣告方法的地方加上 final 就可以 Unchangable

Q2: LOD 幾?
A2: LOD 1 (你可以使用你自己) 由程式碼可知 BasicEngineering class 的 completeCourse () 調用了自己的一些方法 completeMath (), completeSoftSkills () 等

# Q2

Q:
A:

# Q3

Q1: Pattern?
A1: 由第一句 將責任動態的添加至物件上 (Attach additional responsibilities to an object dynamically) 與最後一句 提供彈性的替換子元件以至於添加更多功能 (flexiable alternative to subclassing for extending funtionality) 可知是 Decorator

Q2: Pattern?
A2: 這題太明顯了 第一句 定義一整族的演算法 (Define a family Algorithm) 可以知道是 Strategy

Q3: Pattern?
A3: 建造一整族的相關或獨立的產品 (interface for creating families of related or depenedent) 且不指定他們的 ConcreteClass (Without specifying their concrete class) 可以知道是 Abstract Factory

Q4: Pattern?
A4: 表現於物件結構 (performed on the elements of an object structure) 可以先得知是 Structual Pattern ,接者看 定義新操作 且不需要改變元素的操作 (define new operation without changing the classes of elements on which it operates) 可以得知是 Visitor

Q5: Pattern?
A5: 用同一個 Constructor 可以產生不同呈現 (the same construction process can create different representations) 由此可知是 Builder

Q6: Pattern?
A6: 使用共用來有效支援細粒度的物件 可知是 Flyweight

Q7: Pattern?
A7: 捕捉與外部化物件內部的狀態所以物件可以在往後被存在狀態裡 可以知道是 Memento

Q8: Pattern?
A8: 看最後一句 自動通知與更新 (notified and updated automatically) 可以知道是 Observer

Q9: Pattern?
A9: 第一句 樹狀結構內有聚合物件 (Compose object into tree structure) 可以知道是 Composite

Q10: Pattern?
A10: 依序存取聚合物件 (access the elements of an aggregate object seqentially) 可以知道是 Iterator

Q11: Pattern?
A11: 將客戶參數化 (parameterize client) support undoable operation (支援反回上一步的操作) 可以知道是 Command

Q12: Pattern?
A12: 讓 subclass 去決定要去實例化哪個物件 (let subclasses decide which class to instantiate) 可以知道是 Factory method

# Q4

Q: 請寫出程式碼去表示 Simple Factory VS Factory Method
A:

Factory Method:
在工廠方法我們 Client Code (Main) 會委託 ConcreteFactory 直接去生產我們需要的產品且透過參數去產出不同的產品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface CarFactory {
String getCar();
}
class TaxiFactory implements CarFactory{
@Override
public String getCar() {
return new Taxi();
}
}

class BusFactory implements CarFactory{
@Override
public String getCar() {
return new Bus();
}
}

Simple Factory:
在簡單工廠模式 Client Code (Main) 透過 CarFactoy Interface 去知道有 getCar 方法 且 New 出需要的工廠且每個工廠會各自生產不同的產品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public class CarSimpleFactory {
public String getCar(String carName){
switch (carName){
case "A":
return "Car A";
case "B":
return "Car B";
case "C":
return "Car C";
default:
return null;
}
}
}

# Q5

Q1: 相同的對待 Graphics (Composite) 跟 Text (Leaf)
A1: 用 Composite Pattern 首先建立 Graphics (Composite) 跟 Text (Leaf) 的共同 interface Glyph 接者定義元件們需要的方法製 interface 上 這麼一來不論 Leaf (Text) or Graphics (Composite) 都可以被認定為 Glyph 且被統一對待,此外假設使用透明化設計 transparent 只能在 Composite 上使用但 leaf 不能 我們將 leaf 的實作方法拋出 exceprion or return null

Class Diagram:

Q2: 我們有很多的格式化演算法各有不同優缺點?一個需要去取捨的點是格式化品質與格式化速度之間
A2: 我們可以將不同的演算法封裝至不同的 class,且共用一個 Formatting 的 Interface,接者讓需要用到格式化物件的 class 透過 setter 設置需要的 ConcreteFormatting

class Diagram:

Q3: 有關建立 UI, 我們如何應用透明化的概念封裝所有被其他 glyph 建立的 glyph
A3: 我們可以使用 Composite Pattern,且使用透明化的設計讓 Client Code 可以得知 Graphics Text or 其他子元件有這些方法可以使用,且如 getChild () insert () remove () 方法可以透過 Composite 物件 (Graphics) 來管理位於該 Graphics 底下的所有 Glyph,且由於使用透明化設計 Text 或者其他 leaf 元件也需要有 Glyph 宣告的所有方法,那實際上會以 throw Exception 的方式實作,避免無意義的操作。

Class Diagram 同 Q1

Q4: 表現一組物件結構元素的操作,此 Pattern 可以讓你去定義新操作且不用改變元素們 class 的操作。
A4: 我們的元素可以有不同種類的主題,雖然這些元素的主題內容都不相同,但他們要做的事情都是一樣的,所以我們用 Abstract Factory 建立一整族的相關元素。

class Diagram:

Q5: 分開建構一個複雜的物件來表現他以達到同個建構過程可以建立不同的表達效果
A5: 不同的作業系統會有不同的方式去實作他的行為像是畫圖片或系統檔案結構,所以我們不能夠使用 Abstract Factory 去解決這個問題,我們可以用 Bridge 來替代將原本的抽象物件 Abstraction 透過 Implementor 進行解耦,這樣我們可以讓這兩類東西獨立,且 Window 怎麼做會根據 WindowImpl 的實作。

class diagram:

Q6: 使用者透過不同的 UI 包含按鈕與下拉式選單。我們要如何提供不同的機制去存取這些散落的功能且能夠 undo
A6: 文字編輯器一些 action 且我們可以讓這些 action 綁定在元件之中,然而假如我們將 action 擺設在任何地方,整個程式碼就會變得複雜且難以維護,所以我們可以封裝每個 action 成物件,這樣 action 就會變得更有彈性也支援 undo 的功能,我們需要在 action 表現之前將 Receiver 的狀態儲存起來 (這樣 undo 狀態才能回來)

Q7: 有關於拼字檢查與連字符分析.Lexi 是如何去支援分析操作的像是檢查拼字錯誤的字與連字符?我們如何去最小化 class 的數量,當我們添加新方法的是需要去修改嗎?
A7: 假如我們想要檢查拼字或連字符,我需要去迭代所有 Glyph 裏頭的物件,且在迭代之中加入一些的操作,然而當我們需要去修改拼字檢查的操作或是添加新的分析方法,我們就需要高頻率的更改迭代方法。去解決這個問題我們可以使用 Vistor Pattern 去定義操作且不用更改實作操作的物件結構。
此外我們存儲物件的結構是個 Composite 物件 Graphics (Composite) 裏頭會有 Aggregate (聚合) 物件,Aggregate 物件的實際操作會透露出來,我們可以在之中套用 Iterator Pattern 去解決操作透漏的問題,且可以存取 Aggregate 物件在不知道實際操作的情況下。


# 109 Quiz 2

# Q1

A1: 最下面的 Customer 需要聯絡 sales manager (銷售經理),那中間有個人幫 Customer 進行轉接,Adapter Pattern 這我不確定

A2: 重點右下角返回至預設系統設定,Memento

A3: 台上 Auctioneer (拍賣者) 進行拍賣,當台下的 Bidder (出價者) 發生出價 (bid) 改變,Auctioneer 會廣播 (Broadcast) 出當前更高的出價 Observer

A4: 送分題 右上角 ClassName 有 Iterator 方法出現 Next () Iterator

A5: 圖中可以看出系統中有 Java Module (模組) 與 C++ Module (模組) 重點中間是依靠 JNI (Java 原生介面) 來將來者不同的生態進行串界 Adapter

A6: 由於圖中是指程式語言 (Java,Python) 的 Complie 過程,都相同有步驟,且看起來不需要行為 (不是 Behavior Pattern) Builder 可以訂製共同介面來宣告步驟,再交由不同 subClass 進行過程的實作

A7: 使用者要使用手機 App 的服務需要經由一連串的 Layer (層級) 進行處理請求 Chain Of Responsebility

A8: 題目敘述 多種 (Multiple) 可替換的 (interchangleable) 武器去攻擊敵人 Strategy 不是 Bridger 的原因,由於武器可以使用且使用行為會制定在 Concrete class 中還是 Strategy 較為合適。

A9: 右邊敘述 有效率地使用共享的大量細粒度物件 很明顯是 Flyweight

A10 Class Diagram 中 共通 Class,且 BaseWeapon 是指真正的槍械武器,但 WeaponAccessory 之下都是一些槍枝配件 (槍托等),而槍枝配件是可以疊加在武器 (Weapon) 上的因此 Decorator

# Q3

A1: 避免物件從外部實例化

A2: 為了 thread-safe 使用如下圖的 Lazy Singleton Pattern 無法達成,應該使用 Eager Singleton Pattern 制定 getInstance 方法 且在方法名稱加上 Synchronized 保證物件在所有的 thread 只會出現一次

A3: 範例程式中沒有透過 getInstance 方法來讓外界取得 Captain Instance 且在 Constructor 為 Private 的情況下,Captain instance 永遠不會被實例化,且在未使用保留子 Synchronized 的情況下無法讓程式 thread-safe

A4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final class Captain{
private static Captain captain;
static int numberOfInstance =0;

private Captain(){
numberOfInstance++;
System.out.println("Number of instances at this momonet="+numberOfInstance);
}
public Captain static synchronized getInstance(){
if(captain == null){
captain = new Captain();;
System.out.println("New Captain is elected for your team.");
}else{
System.out.println("You already have a captain for your team.");
}
return captain;
}
}

–or–

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
final class Captain{
private static Captain captain;
static int numberOfInstance =0;

private Captain(){
numberOfInstance++;
System.out.println("Number of instances at this momonet="+numberOfInstance);
}
public Captain static getInstance
if(captain == null){
synchronized (Captain.class){
if(captain == null){
captain = new Captain();;
System.out.println("New Captain is elected for your team.");
}
}
}
return captain;
}
}

# Q4 (ProtoType 沒教過)

A1: Clonealbe
A2: clone()
A3: CloneNotSupportedException
A4: super.clone();
A5: Car is: Green Nano and its price is NTD.350000.
Car is: Ford Yellow and its price is NTD.550000.

# Q5 (ProtoType 沒教過)

A: 當我們要複製的物件他只有基礎屬性時或者他的關係並不是很重要去需要為關係進行複製,那麼使用淺複製即可,當你需要複製的物件由物件而組成且需要紀錄物件之間的關係時就需要使用深複製,這麼一來就可以保證我們改變物件的屬性物件時也會去影響有關係的物件,但假設物件屬性中都不支援複製,cloneable interface 那就無法使用深複製只能使用淺複製。

# Q6

A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public interface DBImplInterface{
StateDiagram getDiagram(String name);
void saveDiagram(StateDiagram d);
void connectDB();
void disconnectDB();
}
public class RDBImpl implements DBImplInterface{
public StateDiagram getStateDiagram(String name){
connectDB();
StateDiagram statediagram;
//Get StateDiagram Operation;
disconnectDB();
return stateDiagram
}
public void saveDiagram(StateDiagram d){
//save Diagram to RDB
}
public void connectDB(){
//Connect RDB
}
public void disconnectDB(){
//Disconnect RDB
}
}

public class LDAPImpl implements DBImplInterface{
public StateDiagram getStateDiagram(String name){
connectDB();
StateDiagram statediagram;
//Get StateDiagram Operation;
disconnectDB();
return stateDiagram
}
public void saveDiagram(StateDiagram d){
//save Diagram to LDAP
}
public void connectDB(){
//Connect LDAP
}
public void disconnectDB(){
//Disconnect LDAP
}
}
public class DBMgr{
DBImplInterface impl;
public DBMgr(DBImplIntrerface impl){
this.impl=impl;
}
public StateDiagram getDiagram(String name){
return impl.getDiagram(name);
}
public void saveDiagram(StateDiagram d){
impl.saveDiagram(d);
}

}
publci class EditController{
DBImplInterface dbImplInterface = new RDBImpl;
DBMgr dbmgr = new DBMgr(dbImplInterface);
StateDiagram stateDiagram;
public void getDiagram(String name){
stateDiagram = dbmgr.getDiagram(name);
}
public void saveDiagram(StateDiagram stateDiagram){
dbmgr.save(stateDiagram);
}
}

# Q7

A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public abstract class RDBImpCMD{
protected Diagram diagram;;
public final void execute(){
connectDB();;
queryDB();
Object result = getResult();;
if(isProcess()){
processResult(result);
}
disconnectDB();
}
public void connectDB(){//Concrete Operation
// Connect to RDB
}
public boid disconnectDB(){//Concrete Operation
// Disconnect to RDB
}
public abstract Object getResult();//Primitive Operation
public abstract void queryDB();//Primitive Operation
public abstract Diagram processResult(Object result);//Primitive Operation
public boolean isProcess(){//Hook Operation
return false;
}
}
public abstract class GetDiagrm extends RDBImpCMD{
public Object getResult(){
//get Diagram from RDB and return Object of Diagram
}
public boolean isProcess(){
return true;
}
public Diagram getDiagram(String name){
Diagram diagram;
connectDB;
//Get diagram by name and store in diagrma
disconnectDB;;
return diagram;;
}
}
public class GetStateDiagram extends GetDiagram{
String name;
public GetStateDiagram(String name){
this.name=name;
}
public void queryDB(){
//Query from RDB
}
public Diagram processResult(Object result){
StateDiagram d
//produce statediagram by result
return (Diagram)d;
}
}
public class GetClassDiagrma extends GetDiagram{
String name;
public GetStateDiagram(String name){
this.name=name;
}
public void queryDB(){
//Query from RDB
}
public Diagram processResult(Object result){
StateDiagram d
//produce statediagram by result
return (Diagram)d;
}
}
public abstract class SaveDiagram extends RDBImpCMD{
public Object getResult(){
//get result from RDB abd return it
}
public Diagram processResult(Object result){
return null;
}
}
public class saveClassDiagram extends SaveDiagram{
ClassDiagram d;
public SaveClassDiagrma(ClassDiagram d){
this.d=d;
}
public void queryDB(){
//Query from RDB
}
}
public class saveStateDiagrma extends SaveDiagram{
StateDiagrma d;
public SaveStateDiagrma(ClassDiagram d){
this.d=d;
}
public void queryDB(){
//Query from RDB
}
}

# Q8

A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public interface Command{
void execute();
void undo();
}
public class CuttingCommand implements Command{
Stack<Memento> mementoStack;
Editor editor;
public CuttingCommand(Editor editor){
this.editor =editor;
this.mementoStack = new Stack();
}
public void execute(){
Memento m = this.editor.createMemento();
mementoStatck.push(m);
//Cutting Operation in Editor
}
public void undo(){
Memento m = mementoStack.pop();
editor.restoreMemento(m);
}
}
public class PastingCommand implments Command{
Stack<Memento> mementoStack ;
Editor editor;
public PastingCommand(Editor editor){
this.editor=editor;
this.mementoStack = new Stack<Memento>();
}
public void execute(){
Memento m = editor.createMemento();
mementoStack.push(m);
//Pasting Operation to Editor
}
public void undo(){
Memento m = mementoStack.pop();
editor.restoreMemento(m);
}
}
public class Memento{
String state;
public Memento(State state) {
this.state = state;
}
public String getState(){
return this.state;
}
}
public class Editor{
String state;
public void setState(String state){
this.state=state;
}
public String getState(){
return this.state;
}
public Memento createMemento(){
Memento m = new Memento(state);
return m;
}
public void restoreMemento(Memento m){
this.state = m.getState();
}
}
public class CommandManager{
Stack<Command> pastCommandStack = new Stack();
Stack<Command> futureCommandStack = new Stack();
public execute(Command c){
pastCommandStack.push(c);
futureCommandStack.remove(c);
c.execute();
}
public void undo(){
Command c = pastCommandStack.pop();
futureCommandStack.push(c);
c.undo();
}
}
public class EditorController{
CommandManager cmdMgr = new CommandManager();;;
Editor editor;
public void doCutting(){
Command c = new CuttingCommand(editor);
cmdMgr.exexute(c);
}
public void doPasting(){
Command c = new PastingCommand(editor);
cmdMgr.execute(c);
}
public void undo(){
cmdMgr.undo();
}
}

# 108 Test3

# 很懶

更新於