四層架構 (Four Layers)
架構圖
┌─────────────────────────────────────────────┐
│ Presentation Layer (UI) │
│ Angular Components, Controllers │
├─────────────────────────────────────────────┤
│ Application Layer (Use Cases) │
│ Business Logic, Orchestration │
├─────────────────────────────────────────────┤
│ Domain Layer (Entities) │
│ Business Rules, Data Models │
├─────────────────────────────────────────────┤
│ Infrastructure Layer (External) │
│ Database, API, File System │
└─────────────────────────────────────────────┘
各層職責
1. Domain Layer(最核心)
包含: Entities, Value Objects, Domain Events, Repository Interfaces
規則: 不依賴任何外層
// domain/entities/user.ts
export class User {
constructor(
public readonly id: string,
public readonly email: string,
private _name: string
) {
this.validate();
}
private validate(): void {
if (!this.email.includes('@')) {
throw new Error('Invalid email');
}
}
changeName(name: string): void {
if (name.length < 2) throw new Error('Name too short');
this._name = name;
}
}
// domain/repositories/user-repository.ts
export interface UserRepository {
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
save(user: User): Promise<void>;
}
2. Application Layer(業務流程)
包含: Use Cases, DTOs, Application Services
規則: 只依賴 Domain Layer
// application/use-cases/create-user.ts
export class CreateUserUseCase {
constructor(private userRepo: UserRepository) {}
async execute(request: CreateUserRequest): Promise<UserResponse> {
// 1. 檢查是否已存在
const existing = await this.userRepo.findByEmail(request.email);
if (existing) throw new Error('User already exists');
// 2. 建立使用者
const user = new User(generateId(), request.email, request.name);
// 3. 儲存
await this.userRepo.save(user);
// 4. 回傳
return { id: user.id, email: user.email };
}
}
// application/dtos/create-user-request.ts
export interface CreateUserRequest {
email: string;
name: string;
}
3. Infrastructure Layer(外部資源)
包含: Repository Implementations, External API Clients, Database
規則: 實作 Domain 定義的介面
// infrastructure/repositories/postgres-user-repository.ts
import { UserRepository } from '../../domain/repositories/user-repository';
import { User } from '../../domain/entities/user';
export class PostgresUserRepository implements UserRepository {
constructor(private pool: Pool) {}
async findById(id: string): Promise<User | null> {
const result = await this.pool.query(
'SELECT * FROM users WHERE id = $1', [id]
);
if (result.rows.length === 0) return null;
return this.toDomain(result.rows[0]);
}
async save(user: User): Promise<void> {
await this.pool.query(
'INSERT INTO users (id, email, name) VALUES ($1, $2, $3)',
[user.id, user.email, user.name]
);
}
private toDomain(row: any): User {
return new User(row.id, row.email, row.name);
}
}
4. Presentation Layer(使用者介面)
包含: UI Components, Controllers, API Routes
規則: 調用 Application Layer
// presentation/controllers/user-controller.ts
export class UserController {
constructor(private createUserUseCase: CreateUserUseCase) {}
async create(req: Request, res: Response): Promise<void> {
try {
const result = await this.createUserUseCase.execute({
email: req.body.email,
name: req.body.name
});
res.json(result);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
依賴注入 (Dependency Injection)
所有依賴都從外部注入,不內部 new:
// bootstrap.ts(應用程式啟動點)
const pool = new Pool({ connectionString: DB_URL });
const userRepo = new PostgresUserRepository(pool);
const createUserUseCase = new CreateUserUseCase(userRepo);
const userController = new UserController(createUserUseCase);
// Web 框架路由
app.post('/users', (req, res) => userController.create(req, res));
目錄結構範例
src/
├── domain/
│ ├── entities/
│ │ ├── user.ts
│ │ └── order.ts
│ ├── repositories/
│ │ ├── user-repository.ts
│ │ └── order-repository.ts
│ └── events/
│ └── user-created.ts
│
├── application/
│ ├── use-cases/
│ │ ├── create-user.ts
│ │ └── get-user.ts
│ ├── dtos/
│ │ ├── create-user-request.ts
│ │ └── user-response.ts
│ └── services/
│ └── email-service.ts
│
├── infrastructure/
│ ├── repositories/
│ │ ├── postgres-user-repository.ts
│ │ └── postgres-order-repository.ts
│ ├── services/
│ │ └── sendgrid-email-service.ts
│ └── database/
│ └── connection.ts
│
├── presentation/
│ ├── controllers/
│ │ └── user-controller.ts
│ ├── routes/
│ │ └── user-routes.ts
│ └── middleware/
│ └── auth.ts
│
└── bootstrap.ts