OOAD

 Object-Oriented Analysis and Design 

by Hohshen

目錄

OOA

OO World

OOA

OOA to OOP

Force

Force

DIP, OCP

依賴反轉重構三步驟

1+1~=2

OOD

SOLID

Creational

Behavioral

Structural

Architecture

basic Architecture

DDD design concept

戰略

戰術

地圖

OO World

The world is constructed of objects

  1. identifiability可辨識性

  2. Attributes屬性

  3. Behavior行為(Operation動作操作)

    1. 透過一些行為, 與其他物件發生關係(Relationship)

The world is constructed of objects

what is responsibility

What is an object?

描述著各個物件中的互動

There are too many objects (instances) and we need to classify them!

一群...

1. Relationship 和 object 相同

2. 都有著相同的Responsibility, 並朝著相同目標前進

 

object to class

如果有些不同=>使用abstract class

1. Explain the responsibilities of each class

2. class relationship

Class to Domain Model

What is a domain model(領域模型)

1. Structure

  • Class Diagram

  • Object Diagram

How to create Domain Model

UML (Unified Modeling Language)
統一塑模語言

2. Behavior

  • Sequence Diagram
  • State Machine Diagram(e.g. proxy)
  • Activity Diagram
  • Use Case Diagram

OOA

(Object-Oriented Analysis)

    Phase I: Require Analysis, Create Domain Model

1. Dependency 依賴

2. Association 關聯

  • Aggregation聚合
  • Composition複合

3. Generalization繼承(一般化)

Relationship

如果給你一份需求,

你就能立刻看出需求中涉及的物件/類別以及之間的關係的話,

那麼這就是「架構式思維」的培養基礎

e.g. 我使用鉛筆寫字

I use pencil to write

 Dependency 依賴

 

Human
-------
-------
+ write(pencil:Pencil)
Pencil
-------
-------

e.g. 老師教這個班級

Teacher teach this class

Association 關聯

 

Teacher
-------
-------
+ teach(class:Class):void
Class
-------
-------

? teach ?

e.g. 老師教這個班級

Teacher teach this class

Association 關聯

 

Teacher
-------
-------
+ teach(class:Class):void
Class
-------
-------

1 teach *

加上數量

  1. how many object of teach relationshiop. focus on teach operation

    1. How many classes can a teacher teach? n-th class

    2. How many teachers can there be in a class? 1-th teacher

  2. is an one-to-many association

e.g. 學生修課, 並取得期末成績
Every student who takes this class will get a final score

Association 關聯

 

Student
-------
-------
+ takeClass(class:Class):void
Class
-------
-------

* take *

Every student who takes this class

e.g. 學生修課, 並取得期末成績
Every student who takes this class will get a final score

Association Class關聯

 

Student
-------
-------
+ takeClass(class:Class):void
Class
-------
-------

* take *

(relationship) will get a final

TakeClass
-------
- finalScore: int
-------

1 get 1

e.g. A man is a human, and a woman is also a human

Generalization 繼承(一般化)

 

Woman
-------
-------
Man
-------
-------
Human
-------
-------

e.g. Both men and women will think.

Generalization 繼承(一般化)

Woman
-------
-------
think():void
Man
-------
-------
think():void
/Human
-------
-------
+ /think():void

Abstract class (italics)
Abstract Method (italics)

箭頭

A 知道 B    A--->B

AB相互    A<--->B  or A---B

知道使用的意思

來點範例吧!

Q1: secret love

0...* love 1

請表示暗戀關係
(限定人與人, 暫不考慮人獸)

Q1: secret love (1)

(many)Boy love a Girl, But girl not know.

Boy
--------
--------
+ love():void
Girl
--------
--------
+ love():void

0...* crush1

Q1: secret love (2)

(many)Boy love a Girl, But girl not know.

Boy
--------
--------
+ love():void
Girl
--------
--------
+ love():void

0...* crush 1

Boy
--------
--------
+ love():void
Girl
--------
--------
+ love():void

0...* crush 1

Boy
--------
--------
+ love():void
Girl
--------
--------
+ love():void

0...* crush 1

Person
--------
--------
+ love():void

- 暗戀者

- 被暗戀者

Aggregation 聚合

Person
--------
--------
+ buy(house:House):void
House
--------
--------

1 Buy 0...*

擁有者獲得方塊

  1. e.g. One person can buy many houses

自住客

屯房客

Composition 複

Directory
--------
--------
+ contain(file:File):void
File
--------
--------

1 contain 0...*

Q1: Can't files be independent of directories?
Q2: When deleting a folder, will the files also be deleted?
Yes => use combination

擁有者獲得方塊

e.g. The directory on my computer contains many files

整理

Dependency

Generalization

Association

Aggregation

Composition

/Relationship
Association
Aggregation
Composition
Generalization
Dependency

重點在於「知識」, 不是程式實作

物件導向分析心法

這樣在程式中 work 嗎?

這樣的設計好嗎?

會不會有太多的條件式?

這邊是不是要套用什麼模式?

這邊是不是太多依賴?太過耦合?....

領域知識包含:定義、規範、邏輯、行為/流程

1. 捕捉知識點: 捕捉各個腳色

2. 建立關係

OOA to OOP

Let’s start OOA to OOP

(Object-Oriented programming)

Basic class

class Student{
	private id: number
    private age:number
    
    constructor(id:number,age:number){
    	this.id=id;
        this.setAge(age);
    }
    
    public setAge(age:number):void{
    	if(age<7||age>150){
        	throw new IllegaArgumentExecption("Age muse be with 7~150");
        }
        this.age=age;
    }
    
    public study():void{
    	console.log("Study")
    }
}
class IllegalArgumentExecption extends Error{
	consturctor(message:string){
    	super(message)
    }
}

getter/setter不會特別寫在Class Diagram

使用setter做Initialization verification

Student
--------
- id: int
- age: int {7<=age<=150}
--------
+study():void

OOA to OOP - Dependency

 

class Student{
	private id: number
    private age:number
    
    constructor(id:number,age:number){
    	//...
    }
    
    private setAge(age:number):void{
        //...
    }
    
    public study(book:Book):void{// here
    	console.log("Study" + book.getName());
    }
}
Student
--------
- id: int
- age: int {7<=age<=150}
--------
+study(book:Book):void
class Book{
	private name:string
    constructor(name:string){
    	this.name=name;
    }
    public getName(){
    	return this.name;
    }
}
Book
-------
- name:string
-------

Association 1 to n 單向關係

class Student{
	private id: number
    private age:number
    private subjects: Subject[]=[]
    
    constructor(id:number,age:number){
    	//...
    }
    
    private setAge(age:number):void{
        //...
    }
    
    public study(subject:Subject):void{// here
    	console.log("Study" + subject.getName());
        this.subjects.push(subject)
    }
}
Student
--------
- id: int
- age: int {7<=age<=150}
--------
+study(subject:Subject):void
class Subject{
	private name:string
    constructor(name:string){
    	this.name=name;
    }
    public getName(){
    	return this.name;
    }
}
Subject
-------
- name:string
-------

1 study 0...*

使用subject array代表一直有著多個Subject

Association 1 to n 雙向關係

class Student{
    private subjects: Subject[]=[]
    //...
    public study(subject:Subject):void{
    	console.log("Study" + subject.getName());
        this.subjects.push(subject)
        subject.setLearner(this)// here
    }
}
Student
--------
- id: int
- age: int {7<=age<=150}
--------
+study(subject:Subject):void
class Subject{
    private learner:Studnet
	//...
    public setLearner(lerner:Studnet){
    	this.learner=learner
    }
}
Subject
-------
- name:string
-------

1 study 0...*

Subject提供setLearner
Student將自己設為Subject的Learner
雖然會照成循環依賴,

但許多場合中能夠有效地化簡程式複雜度

比較怕的是consturctor的circular dependency

Association Class

class Student{
    private scores: Score[]=[]
    //...
    public setScore(score:Score):void{
    	this.scores.push(score)
    }
}

這次並非相互持有對方,
而是雙方持有同一份註冊紀錄

Student
-------
-------
+ takeClass(class:Class):void
Class
-------
-------

* take *

TakeClass
-------
- finalScore: int
-------

1 get 1

class FinalScore{
	private score:number
    constructor(
    	private class:Class
        private student:Studnet,
        private score:number,
    ){
    	this.class=class;
        this.student=student;
        this.score=score;
    }
}
class Class{
	private scores: Score[]=[]
	public exam(student:Student,score:number){
    	const score=new Score(this,student,score);
        student.setScore(score) //here
        this.setScore(score)	//here
    }
    public setScore(score:Score){
    	this.scores.push(score)
    }
}

Aggregation/ Composition

同理 Association 

Generalization

就是繼承

Force

(Find out the problem)

等等介紹的字

都來自於Design Pattern

品質的快速指引

Pattern的概念

新手

軟體設計的快速指引


老手:

精通模式,內化了設計的本質,

將軟體從束縛中解放

Alexander從數學的觀點把大量建築案例分析,

抽象化成當使用者與建築空間互動中,

提供了253不同解決問題的模式(Pattern)
造就了四人幫GoF"設計模式"聖經

品質是"誕生"出來的,

而非被"人造"出來的

– Alexander

的永恆建築之道

e.g. 花

無論是建築物還是軟體程式,
基於pattern language 的文法,
在限定的context下,
套用patterns 來解決force和problem

孕育出生命力

從而獲得the Quality without a name

 

The Quality without a name

讓“特定品質”自然誕生;

這個種子就是模式語言Pattern Language

Pattern language

使用相同的文法,種出具有相同品質的結果

充滿中國風的建築

如何凸顯中國風? 建築物的元素體現了他的特色

元素: 就是它蘊含的所有模式(e.g. 燕尾脊)

         以及模式與模式之間的關係

把這些關係當作一種文法,

就是所謂的Pattern Language(模式語言)

其實你無法消除這些force的存在,

只能透過建築物的型態(form)的設計

使得這些forces讓他們朝著特定方向釋放而去

如果沒有妥善處理,就會照成彼此衝突,

失去生命力

Force 力(抑鬱的壓力)

從一次次的force中,

順應著force,發展出各式各樣的模式,

打造出各式建築

Pattern

1. 在Context下找到Problem.
2. 這個Problem下遇到了什麼Force,
以造成此Problem.

3. 將每個Force提出解決方案Solution

4. 最後得到了Resulting Context

流程

a pattern is a solution to a problem in a context
每個模式都次在每個情境下,針對一個問題提出的解決方案

context: 你目前關心的項目(情境)

e.g. context: 肥宅工程師
     problem: 如何變瘦?
     force: 1. 重訓好無聊 2. 效果慢,容易放棄
     solution: 改上拳擊課
     resulting context: 不但變瘦,還學習到了拳擊技巧

=>肥宅變瘦模式

Form

不過我們無法透過文字來描述這些solution,

所以必須繪製出這些solution的形狀 — form 以表達這個模式

所以我們會使用form來代稱solution,
最常來表達form的就是使用uml

 

One pattern at a time

重構三步驟

遇到Problem=> 尋找pattern,找到對應的pattern

基於pattern的語法, 藉由[重構三步驟]來重構

 

1. Encapsulation what varies 封裝變動處

2. Abstract common behaviors 萃取共同行為

3. Delegation/Composition 委派或複合

 

這三個步驟,幫你形塑出了該pattern的form,

化解了所有forces

重構三步驟

「萃取」 (Abstract)

Person
-------
-------

OOA

/Car
-------
+ 載(person:Person):void
+ /發動引擎():void
-------
/Motorcycle
-------
+ 載(person:Person):void
+ /發動引擎():void
-------
電動車
-------
+ 發動引擎():void
-------
油車
-------
+ 發動引擎():void
-------
普通機車
-------
+ 發動引擎():void
-------

「萃取」 (Abstract)

Person
-------
-------

OOD

電動車
-------
-------
+ 發動引擎():void
油車
-------
-------
+ 發動引擎():void
普通機車
-------
-------
+ 發動引擎():void
<<interface>> 交通工具
-----
-----
+ 發動引擎():void
+ 載(person:Person):void
/Motorcycle
-------
-------
+ 載(person:Person):void
+ /發動引擎():void
/Car
-------
-------
+ 載(person:Person):void
+ /發動引擎():void

來個範例吧!

Problem: 如何讓英雄有不同的行為組合,不造成繼承上的組合爆炸

public void attack(hero:Hero){
	switch(attackType){
    	case "NormalAttack":
        	hero.damage(10)
        case "MagicAttack": 
        	hero.damage(20)
        case "UltimateAttack":
        	hero.damage(30)
    }
}

Force:
1. 行為變動性
2. 維護性
3. 擴充性

1. Encapsulation what varies 封裝變動處

public void attack(hero:Hero){
	switch(attackType){
    	case "NormalAttack":
        	hero.damage(10)
        case "MagicAttack": 
        	hero.damage(20)
        case "UltimateAttack":
        	hero.damage(30)
    }
}
class NormalAttack
	+ attack(attacker:Hero, attacked:Hero):void
}
class MagicAttack
	+ attack(attacker:Hero, attacked:Hero):void
}
class UltimateAttack
	+ attack(attacker:Hero, attacked:Hero):void
}

決定屬性(Attribute)和行為(Behavior)的可視範圍(Visibility)
=>透過封裝隱藏了一些屬性和行為

針對每個行為變種,創建一個類別來去封裝他

2. Abstract common behaviors 萃取共同行為

class UltimateAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}

查看這些class的共同處,生出interface

透過介面,是無法看出完整atack行爲的

class NormalAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}
class MagicAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}
interface AttackType{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}

3. Delegation/Composition 委派或複合

class UltimateAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}

委派

hero委派atack職責,給attackType介面

class NormalAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}
class MagicAttack{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}
interface AttackType{
	+ attack(
    	attacker:Hero,
     	attacked:Hero
    ):void
}
Hero
-------
hp:int
attackType:AttackType
-------
attack(hero:Hero):void

resulting context- 成功的依賴反轉

UltimateAttack
NormalAttack
MagicAttack
AttackType
Hero
UltimateAttack
NormalAttack
MagicAttack
Hero

因為依賴的方向確實被反轉了
原本hero 依賴attack行為區塊

resulting context-達到1+1~=2的效果

最厲害的是透過DI的方式
在不修改Context內部程式碼的前提之下

不斷地擴充新的handler來支援新的需求(OCP)

Context

Handler

Handler

Handler

Handler

n 倍效率

學會察覺到Forces

真正對軟體設計入木三分的人所設計出的軟體
沒有一行程式碼是多餘的, 要怎麼做到這件事呢?

需要大量的練習,藉由一次次的經驗

來鍛鍊察覺forces的能力,
並且清晰地說出你究竟是套用了何種pattern,來解決forces

避免Over Design

工程師技能 戰鬥技能
熟習程式語言 強壯身體
熟悉後端知識 懂武術
solid + ooad 懂排陣法
Clean Arch 懂兵法

目標: 解耦合高內聚

目標: 贏的漂亮

  1. got a require document

  2. OOA

  3. OOP version 1

  4. feel something wrong! find out force and problem

  5. OOD use design pattern solve force

  6. OOP version 2

You got a message!

Every design needs to be drawn first! remember forever!

Architecture thinking: text to tech

The architectural thinking of software engineering is based on the relationship of text to objects and classes.

Thank You!

Questions?

OOD

TODO

SOLID

TODO

Behavioral

TODO

Structural

TODO

Creational

Architecture

OO

By Shen Hoh

OO

  • 90