2023/03/20

學習使用轉接器模式 (Adapter Pattern) 處理 API 介面不符的情況 - 使用 Delphi


轉接器模式 (Adapter Pattern)  適合的場景

近年來,隨著跨平台開發的需求增加,我們必須考慮如何在不同的環境下呈現出一致的介面,而 轉接器模式 (Adapter Pattern) 正是解決這個問題的好方法。

Adapter 模式是設計模式中常用的一種模式,它能夠讓原本不相容的兩個類別能夠一起工作,是將一個類別的介面轉換成客戶希望的另一個介面的模式。今天我們來看一個 Delphi 中使用 Adapter 模式的範例。

假設我們正在開發一個音樂播放器應用程式,需要使用一個第三方音樂函式庫來播放音樂,但這個庫的介面不符合我們的應用程式的需求,我們需要使用 Adapter 模式來解決這個問題。

Delphi 轉接器模式 (Adapter Pattern)  的範例:將不相容的介面轉換成符合應用程式需求的介面

首先,我們需要建立一個播放器介面,它必須要符合我們應用程式的需求,比如有播放、暫停、停止等功能:


type
  IPlayer = interface
    procedure Play;
    procedure Pause;
    procedure Stop;
  end;

然後,我們需要建立一個使用第三方音樂函式庫的播放器,但它的介面不符合我們應用程式的需求:


type
  TThirdPartyPlayer = class
    procedure Start;
    procedure Halt;
    procedure End;
  end;

現在,我們可以建立一個 Adapter 類別,將 TThirdPartyPlayer 的介面轉換成符合我們應用程式需求的 IPlayer 介面:


type
  TPlayerAdapter = class(TInterfacedObject, IPlayer)
  private
    FThirdPartyPlayer: TThirdPartyPlayer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Play;
    procedure Pause;
    procedure Stop;
  end;
  
constructor TPlayerAdapter.Create;
begin
  FThirdPartyPlayer := TThirdPartyPlayer.Create;
end;

destructor TPlayerAdapter.Destroy;
begin
  FThirdPartyPlayer.Free;
  inherited;
end;

procedure TPlayerAdapter.Play;
begin
  FThirdPartyPlayer.Start;
end;

procedure TPlayerAdapter.Pause;
begin
  FThirdPartyPlayer.Halt;
end;

procedure TPlayerAdapter.Stop;
begin
  FThirdPartyPlayer.End;
end;

現在,我們可以使用 TPlayerAdapter 類別來播放音樂了:


var
  Player: IPlayer;
begin
  Player := TPlayerAdapter.Create;
  Player.Play;
  Player.Pause;
  Player.Stop;
end;

如此一來,我們就成功地使用 Adapter 模式來將原本不相容的介面轉換成了符合我們應用程式需求的介面。

總結

Adapter 模式是一種非常實用的設計模式,能夠讓不相容的類別能夠一起工作,提高程式的彈性和可擴展性。在實際應用中,我們可以使用 Adapter 模式來解決許多問題,例如:

  • 一些舊的程式碼需要被重用,但是與新的系統不相容。
  • 需要在現有的系統上加入新的功能,但是無法修改現有的代碼。
  • 需要整合多個不同的系統,但是它們之間的介面並不相同。 

Adapter 模式的實現方式有很多種,例如類別 Adapter 和物件 Adapter。選擇哪種方式實現取決於具體的應用場景和需求。

在 Delphi 中,我們可以使用類別 Helper 或者繼承來實現 Adapter 模式。在使用時,我們需要根據具體的需求選擇適合的實現方式。

綜上所述,Adapter 模式是一種強大的設計模式,能夠幫助我們解決很多問題。如果您希望提高程式的彈性和可擴展性,那麼學習和應用 Adapter 模式是非常有益的。

2023/03/15

用Delphi體驗簡單工廠模式


簡單工廠模式是一種常用的創建型設計模式,它提供了一個統一的工廠方法,根據傳入的參數來創建不同的產品物件。

具體來說,簡單工廠模式通常包含以下角色:

  • 產品(Product):需要創建的具體產品。
  • 工廠(Factory):負責創建產品的工廠,包含一個靜態的工廠方法,根據客戶端傳入的參數創建對應的產品。
  • 客戶端(Client):使用工廠創建產品的客戶端。
  • 簡單工廠模式的核心是工廠方法,它負責根據客戶端傳入的參數創建對應的產品。客戶端不需要知道具體的產品是如何創建的,只需要知道傳入什麼參數就可以得到對應的產品。

在設計軟體時,我們常常需要創建不同的物件,而這些物件通常有共同的介面或繼承關係。當我們需要創建這些物件時,可以使用簡單工廠模式。

2023/03/13

第一次玩轉 Git 就上手


前陣子在調整 Synology NAS 主機時,發現裡面有個「Git Server」套件。心想 SVN 玩久了,也該了解新東西,看看現在新的版本控制是怎麼玩的。

2023/03/10

Delphi 11 新特性:Array 強化操作功能


今天我們來談談 Delphi XE7 開始支援的動態陣列處理,讓我們可以更輕鬆地處理陣列的新增、刪除、排序等操作。

首先,我們先來看一個簡單的例子:

2023/03/09

Delphi 11 新特性:在函式內宣告變數


在 Delphi 11 中,引入了一個新特性,允許在函式內宣告變數。這種新特性讓開發人員更靈活地宣告變數,使得程式更簡潔,易於閱讀和維護。本文將為您介紹這個新特性,以及如何在 Delphi 中使用它來編寫更好的程式。

2022/12/28

NestedDataSets in ClientDataSets


Overview

The nested dataset feature of ClientDataSet is used to solve the Master-Details design pattern in which a TDataSet field is inserted into the column list. This feature has always been considered a magical technique.

However, the core of database technology is still SQL, so let's take a look at how Delphi uses SQL to pull data in the nested dataset mode.

Surprisingly, the way to pull data is to fetch all details to the client-side at once when fetching data from the header.

2022/08/12

Creating Modern JSON Configuration Files Using Delphi

English

Recently, EMBT published an interesting article in their official news: "This Is How To Store Cross Platform App Settings In JSON" by the Softacom Information team. This emerging team collects and publishes articles from Delphi enthusiasts worldwide, so it's unclear who the original author is.

The article discusses that in addition to XML (Extensible Markup Language) and INI (Initial) formats, modern cross-platform applications often use JSON for configuration files, with Visual Studio Code as a classic example.

Visual Studio Code Workspace Settings File

The article pointed out that Delphi provides two JSON libraries: JSON Objects Framework and Readers and Writers JSON Framework. The author also mentioned the most widely used alternative open-source option, X-SuperObject, provided by Turkish engineer Onur YILDIZ. It's interesting to note that the JSON Objects Framework provides JSON Marshaling/Un-Marshaling, so what makes it different from X-SuperObject?

Delphi developers are spoiled for choice when it comes to using JSON. Realy?

The author complains that Delphi engineers have been spoiled by the official JSON frameworks. Is that true?

The article points out that Delphi provides two JSON libraries: JSON Objects Framework and Readers and Writers JSON Framework. As an alternative, the author suggests using the widely popular open-source variant X-SuperObject by Turkish engineer Onur YILDIZ. Curiously, JSON Objects Framework provides JSON Marshaling/Un-Marshaling, so how does it differ from X-SuperObject?


Example using JSON Objects Framework

 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
TContact = class(TObject)
  public
    Name: string;
    Age: Integer;
    function ToString: string; override;
  end;
 
procedure TForm1.JSONMarshalClick(Sender: TObject);
var
  LContact: TContact;
  oMarshaller: TJSONMarshal;
  crtVal: TJSONValue;
begin
  LContact := TContact.Create; //our custom class
  LContact.Name:='Hello Eden';
  LContact.Age := 20; //fill with some data
  oMarshaller := TJSONMarshal.Create(TJSONConverter.Create); //our engine
  crtVal := oMarshaller.Marshal(LContact); //serialize to JSON
  try
    Memo1.Text := crtVal.ToString; //display
  finally //cleanup
    FreeAndNil(LContact);
    FreeAndNil(oMarshaller);
    crtVal.Free;
  end;
end;

Example execution result using JSON Objects Framework

1
2
3
4
5
6
7
8
{
  "type": "Unit2.TContact",
  "id": 1,
  "fields": {
    "Name": "Hello Eden",
    "Age": 20
  }
}

Example execution result using JSON Objects Framework

The JSON format produced by TObject using the JSON Objects Framework (JOF) is not as intuitive as the one produced by X-SuperObject. Users might need some time to learn the JOF format to manage their configurations.

This has to do with the original purpose of JOF. Around 2009, Delphi 2009 made a transition in DataSnap Framework from XML RPC to JSON RPC. As mentioned earlier, JOF was initially created to serve DataSnap, among other things, such as handling Delphi TObject's strong typing. Therefore, the format produced by JOF is not a weakly-typed compatible JSON format.

Why doesn't JOF produce widely accepted JSON formats?

So, the author's claim that Delphi engineers are spoiled by the two built-in JSON frameworks is not baseless. After getting used to Delphi's native tools, it may be difficult to accept content that deviates from the "Delphi standard."

Creating your desired format using JOF

Knowing that the built-in JOF won't produce a generic JSON format, you can still create your own. Have you heard of TDBXJSONTools? It can be used to convert TDataSet to JSON, so let's add TObject-to-JSON functionality to it!

TDBXJSONToolsHelper adds ObjToJSON functionality

The original example is excellent and deserves a 5-star rating. I modified the example into a VCL project and replaced X-SuperObject usage with JOF, such as in the configuration file loading section:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
procedure TMyProgSettings.LoadFromFile(AFileName: string = '');
var
  LJObj: TJSONObject;
begin
  if AFileName = '' then
    AFileName := GetDefaultSettingsFilename();
 
  if not FileExists(AFileName) then
    Exit;
 
  LJObj := TJSONObject.Create;
  try
    if LJObj.Parse(TFile.ReadAllBytes(AFileName), 0) > 0 then
    begin
      // Magic method from Eden's TDBXJSONToolsHelper unit
      TDBXJSONTools.JsonToObj(LJObj, Self);  
    end;
  finally
    LJObj.Free;
  end;
end;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
procedure TMyProgSettings.SaveToFile(AFileName: string = '');
var
  Json: string;
begin
  if AFileName = '' then
    AFileName := GetDefaultSettingsFilename();
 
  // Magic method from Eden's TDBXJSONToolsHelper unit
  with TDBXJSONTools.ObjToJSON(Self) do
  begin
    Json := ToJson;
    TFile.WriteAllText(AFileName, Json, TEncoding.UTF8);
    Free;
  end;
end;

Conclusion

Being "spoiled" by JOF is, in my opinion, a blessing. JOF is a framework well worth learning, and X-SuperObject offers even more features for JSON writing. If you frequently need to write JSON objects, X-SuperObject will definitely win your heart. Additionally, I enjoyed the original author's example of a login process using a while loop to control the login window; it's a great concept to learn.

You can download the TDBXJSONToolsHelper and VCL example program from my Github website: https://github.com/Eden5Wu/HelperClass/tree/master/Demo-JSON/JsonMarshalling

In summary, both the JSON Objects Framework (JOF) and X-SuperObject have their own unique advantages when working with JSON in Delphi. Developers should choose between them based on their specific needs and preferences.

For developers familiar with the Delphi style, JOF provides a familiar environment for working with JSON. However, if you need more control over JSON object writing, then X-SuperObject may be a better choice.

In any case, exploring and learning about the different JSON frameworks available is essential. By understanding their strengths and weaknesses, you can make more informed decisions about which tools to use in your projects.

Remember, practice and experimentation are key to becoming proficient in any programming language or framework. Therefore, don't be afraid to try different approaches and learn from the examples and experiences of other developers in the Delphi community.

中文版:使用 Delphi 寫出現代化 JSON 格式的設定檔案

最近 EMBT 官方新聞出現我很感興趣的文章:This Is How To Store Cross Platform App Settings In JSON,是由 Softacom Information 團隊執筆,這是一個新興團隊,匯整來自全球各地 Delphi 愛好者的文章並發表,所以還不知道真實原作者是誰。

原文作者說明在跨平台應用程式在讀寫設定檔時,除了 XML (Extensible Markup Language) 和 INI (Initial) 外,還有一個現代化應用程式常使用的設定檔格式:JSON,例如 Visual Studio Code 就是一個經典的參考。

Visual Studio Code 工作區設定檔

Delphi developers are spoiled for choice when it comes to using JSON. Realy?

原作控訴 Delphi 工程師已經被官方 JSON 框架寵壞了 (笑),是真的嗎?