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

期中考


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

很懶

更新於