Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

<br/>

Read in different language : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md), [**vi**](localization/vi/README.md), [**bn**](localization/bn/README.md), [**np**](localization/ne/README.md), [**it**](localization/it/README.md), [**da**](localization/da/README.md)
Read in different language : [**zh**](localization/zh/README.md), [**zh-TW**](localization/zh-TW/README.md)
,[**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md), [**vi**](localization/vi/README.md), [**bn**](localization/bn/README.md), [**np**](localization/ne/README.md), [**it**](localization/it/README.md), [**da**](localization/da/README.md)
<br/>

# Introduction
Expand Down
42 changes: 42 additions & 0 deletions localization/zh-TW/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!-- the line below needs to be an empty line C: (its because kramdown isnt
that smart and dearly wants an empty line before a heading to be able to
display it as such, e.g. website) -->

# 設計模式Java版

![Java CI with Maven](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) [](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg) [](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)

# 介紹

設計模式是程式設計師在設計應用程式或系統時,可以用來解決常見問題的最佳且具形式化的實踐方法。

設計模式能透過提供經過測試與驗證的開發範式,加快開發流程。

重複使用設計模式有助於避免那些可能導致重大問題的細微錯誤,同時也能提升程式碼的可讀性,讓熟悉這些模式的開發人員與架構師更容易理解。

# 入門

這個網站展示了 Java 設計模式。這些解決方案由開放原始碼社群中有經驗的程式設計師與架構師所開發。使用者可以透過高層次的描述來瀏覽這些模式,或是直接查看其原始碼。程式碼範例都有詳細的註解,可以視為實作特定設計模式的教學範本。我們使用的是最受歡迎且經過實戰驗證的開放原始碼 Java 技術。

在深入學習這些內容之前,你應該先熟悉各種[軟體設計原則](https://java-design-patterns.com/principles/).

所有設計都應盡可能簡單。建議先從 KISS(Keep It Simple, Stupid)、YAGNI(You Aren’t Gonna Need It)以及 Do The Simplest Thing That Could Possibly Work 這些原則開始。只有在實際需要擴充性時,才應該引入複雜性與設計模式。

熟悉了這些概念,就可以透過以下任一種方式深入研究可用的設計模式:

- 依名稱搜尋特定模式。找不到的話?請[在這裡](https://github.com/iluwatar/java-design-patterns/issues)回報新模式。
- 使用難度標籤: `Performance(效能)` , `Gang of Four(四人幫)`和`Data access(資料存取)` 。
- 使用模式分類`Creational(建立型)` ,`Behavioral(行為型)`和其他类别。


希望你能在這個網站上找到對你的架構有幫助的物件導向解決方案,並且在學習的過程中和我們開發這些方案時一樣感到愉快。

# 如何做出貢獻

如果你願意為這個專案做出貢獻,你可以在我們的[開發者 Wiki](https://github.com/iluwatar/java-design-patterns/wiki)找到相關資訊。我們也會在[Gitter聊天室](https://gitter.im/iluwatar/java-design-patterns)中協助你並回答你的問題。

# 許可證

該項目使用麻省理工學院許可證。


Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@
title: Abstract Document
shortTitle: Abstract Document
category: Structural
language: zh
language: zh-TW
tag:
- Extensibility
---

## 目的

使用动态属性,并在保持类型安全的同时实现非类型化语言的灵活性
使用動態屬性,並在保持型別安全的同時實現非型別化語言的靈活性

## 解释
## 解釋

抽象文档模式使您能够处理其他非静态属性。 此模式使用特征的概念来实现类型安全,并将不同类的属性分离为一组接口
抽象文件模式 (Abstract Document Pattern) 使您能夠處理其他非靜態屬性。此模式使用特性 (trait) 的概念來實現型別安全,並將不同類別的屬性分離為一組介面

真实世界例子
真實世界範例

> 考虑由多个部分组成的汽车。 但是,我们不知道特定汽车是否真的拥有所有零件,或者仅仅是零件中的一部分。 我们的汽车是动态而且非常灵活的
> 考慮由多個部分組成的汽車。但是,我們不知道特定汽車是否真的擁有所有零件,或者僅僅是零件中的一部分。我們的汽車是動態而且非常靈活的

通俗的说
簡單的說

> 抽象文档模式允许在对象不知道的情况下将属性附加到对象
> 抽象文件模式允許在物件不知道的情況下將屬性附加到物件上

维基百科说
維基百科說

> 面向对象的结构设计模式,用于组织松散类型的键值存储中的对象并使用类型化的视图公开数据。 该模式的目的是在强类型语言中实现组件之间的高度灵活性,在这种语言中,可以在不丢失类型安全支持的情况下,将新属性动态地添加到对象树中。 该模式利用特征将类的不同属性分成不同的接口
> 物件導向的結構設計模式,用於組織鬆散型別的鍵值儲存中的物件,並使用型別化的視圖公開資料。該模式的目的是在強型別語言中實現元件之間的高度靈活性,在這種語言中,可以在不遺失型別安全支援的情況下,將新屬性動態地新增到物件樹中。該模式利用特性 (trait) 將類別的不同屬性分成不同的介面

**程序示例**
**程式碼範例**

让我们首先定义基类`Document`和`AbstractDocument`。 它们基本上使对象拥有属性映射和任意数量的子对象
讓我們先定義基礎類別`Document`和`AbstractDocument`。 它們基本上使物件擁有屬性對映 (map) 和任意數量的子物件

```java
public interface Document {
Expand Down Expand Up @@ -74,7 +74,7 @@ public abstract class AbstractDocument implements Document {
...
}
```
接下来,我们定义一个枚举“属性”和一组类型,价格,模型和零件的接口。 这使我们能够为Car类创建静态外观的界面
接下來,我們定義一個列舉 `Property` 和一組關於型別、價格、模型和零件的介面。這使我們能夠為 `Car` 類別創建靜態外觀的介面

```java
public enum Property {
Expand Down Expand Up @@ -110,7 +110,7 @@ public interface HasParts extends Document {
}
```

现在我们准备介绍`Car`。
現在我們準備介紹`Car`。

```java
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
Expand All @@ -121,7 +121,7 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart
}
```

最后是完整示例中的`Car`构造和使用方式
最後是完整範例中 `Car`的建構和使用方式。

```java
LOGGER.info("Constructing parts and car");
Expand Down Expand Up @@ -162,19 +162,21 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart
// door/Lambo/300
```

## 类图
## 類別圖

![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain")

## 适用性
## 適用性

使用抽象文档模式当
在以下情況使用抽象文件模式:

* 需要即时添加新属性
* 你想要一种灵活的方式来以树状结构组织域
* 你想要更宽松的耦合系统
* 需要即時新增新屬性時

## 鸣谢
* 想要一種靈活的方式以樹狀結構組織領域 (domain) 時

* 想要一個更鬆散耦合的系統時

## 參考資料和來源

* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
Expand Down
229 changes: 229 additions & 0 deletions localization/zh-TW/abstract-factory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
---
title: Abstract Factory
shortTitle: Abstract Factory
category: Structural
language: zh-TW
tag:
- Extensibility
---

## 別稱

* Kit (套件)

## 抽象工廠設計模式的意圖

Java 中的抽象工廠模式 (Abstract Factory pattern) 提供一個介面,用於創建一系列相關或相依的物件家族,而無需指定其具體類別,從而增強了軟體設計的模組化與靈活性。

## 抽象工廠模式的詳細解釋與真實世界範例

真實世界範例

> 想像一家傢俱公司,它使用 Java 中的抽象工廠模式來生產多種風格的傢俱:現代風、維多利亞風和鄉村風。每種風格都包含椅子、桌子和沙發等產品。為了確保每種風格內部的一致性,該公司使用了抽象工廠模式。
>
> 在這個情境中,抽象工廠是一個用於創建相關傢俱物件家族(椅子、桌子、沙發)的介面。每個具體工廠(ModernFurnitureFactory、VictorianFurnitureFactory、RusticFurnitureFactory)都實作了這個抽象工廠介面,並創建一組符合特定風格的產品。如此一來,客戶端就可以創建一整套現代或維多利亞風格的傢俱,而無需擔心其實例化的細節。這不僅保持了風格的一致性,也讓更換不同風格的傢俱變得輕而易舉。

簡單來說

> 工廠中的工廠;一個將個別但相關/相依的工廠群組在一起,而無需指定其具體類別的工廠。

維基百科說

> 抽象工廠模式提供了一種方法,可以封裝一組具有共通主題的獨立工廠,而無需指定它們的具體類別。

類別圖

![Abstract Factory class diagram](./etc/abstract-factory.urm.png "Abstract Factory class diagram")

## Java 中的抽象工廠程式碼範例

為了使用抽象工廠模式來創建一個王國,我們需要具有共通主題的物件。精靈王國需要精靈國王、精靈城堡和精靈軍隊;而獸人王國則需要獸人國王、獸人城堡和獸人軍隊。王國中的這些物件之間存在著相依性。

將上述的王國範例轉換為程式碼。首先,我們為王國中的物件定義一些介面和實作。

```java
public interface Castle {
String getDescription();
}

public interface King {
String getDescription();
}

public interface Army {
String getDescription();
}

// Elven implementations ->
public class ElfCastle implements Castle {
static final String DESCRIPTION = "This is the elven castle!";

@Override
public String getDescription() {
return DESCRIPTION;
}
}

public class ElfKing implements King {
static final String DESCRIPTION = "This is the elven king!";

@Override
public String getDescription() {
return DESCRIPTION;
}
}

public class ElfArmy implements Army {
static final String DESCRIPTION = "This is the elven Army!";

@Override
public String getDescription() {
return DESCRIPTION;
}
}

// Orcish implementations similarly -> ...
```

接著,我們為王國工廠定義抽象和實作。

```java
public interface KingdomFactory {
Castle createCastle();

King createKing();

Army createArmy();
}

public class ElfKingdomFactory implements KingdomFactory {

@Override
public Castle createCastle() {
return new ElfCastle();
}

@Override
public King createKing() {
return new ElfKing();
}

@Override
public Army createArmy() {
return new ElfArmy();
}
}

// 獸人 (Orcish) 的實作也類似 -> ...
```
現在,我們可以為我們不同的王國工廠設計一個工廠。在這個範例中,我們創建了 `FactoryMaker`,它負責返回 `ElfKingdomFactory` 或 O`OrcKingdomFactory` 的實例。客戶端可以使用 `FactoryMaker` 來創建所需的具體工廠,而該工廠又會生產出不同的具體物件(繼承自 `Army`, `King`, `Castle`)。在這個範例中,我們還使用了一個 enum 來參數化客戶端將請求哪種類型的王國工廠。

```java
public static class FactoryMaker {

public enum KingdomType {
ELF, ORC
}

public static KingdomFactory makeFactory(KingdomType type) {
return switch (type) {
case ELF -> new ElfKingdomFactory();
case ORC -> new OrcKingdomFactory();
};
}
}
```

這是我們範例應用程式的主函式:

```java
LOGGER.info("elf kingdom");
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
LOGGER.info(kingdom.getArmy().getDescription());
LOGGER.info(kingdom.getCastle().getDescription());
LOGGER.info(kingdom.getKing().getDescription());

LOGGER.info("orc kingdom");
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
LOGGER.info(kingdom.getArmy().getDescription());
LOGGER.info(kingdom.getCastle().getDescription());
LOGGER.info(kingdom.getKing().getDescription());
```

程式輸出:

```
07:35:46.340 [main] INFO com.iluwatar.abstractfactory.App -- elf kingdom
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven army!
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven castle!
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven king!
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- orc kingdom
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc army!
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc castle!
07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc king!
```

## 在 Java 中何時使用抽象工廠模式
在 Java 中,當您遇到以下情況時,請使用抽象工廠模式::

* 系統應與其產品的創建、組合和表示方式無關。

* 您需要用多個產品家族中的其中一個來配置系統。

* 必須同時使用一系列相關的產品物件,以強制保持一致性。

* 您希望提供一個產品的類別庫,只暴露它們的介面,而不是它們的實作。

* 相依物件的生命週期比消費者的生命週期短。

* 相依物件需要使用執行時期的值或參數來建構。

* 您需要在執行時期從一個家族中選擇要使用的產品。

* 新增新產品或家族時,不應要求修改現有程式碼。

## Java 抽象工廠模式教學

* [Abstract Factory Design Pattern in Java (DigitalOcean)](https://www.digitalocean.com/community/tutorials/abstract-factory-design-pattern-in-java)
* [Abstract Factory(Refactoring Guru)](https://refactoring.guru/design-patterns/abstract-factory)

## 抽象工廠模式的優點與權衡

優點:

* 靈活性:無需修改程式碼即可輕鬆切換產品家族。

* 解耦:客戶端程式碼只與抽象介面互動,提升了可移植性和可維護性。

* 可重用性:抽象工廠和產品有助於跨專案的元件重用。

* 可維護性:對個別產品家族的變更是局部的,簡化了更新過程。

權衡:

* 複雜性:定義抽象介面和具體工廠會增加初期的開發開銷。

* 間接性:客戶端程式碼透過工廠間接與產品互動,可能會降低透明度。

## Java 中抽象工廠模式的實際應用

* Java Swing 的 `LookAndFeel` 類別,用於提供不同的外觀與感覺選項。

* Java Abstract Window Toolkit (AWT) 中的各種實作,用於創建不同的 GUI 元件。

* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)

## 相關的 Java 設計模式

* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): 抽象工廠使用工廠方法來創建產品。
* [Singleton](https://java-design-patterns.com/patterns/singleton/): 抽象工廠類別通常被實作為單例
* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): 與抽象工廠類似,但更專注於以靈活的方式配置和管理一組相關物件。

## 參考資料與致謝

* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
* [Design Patterns in Java](https://amzn.to/3Syw0vC)
* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq)
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3HWNf4U)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading