搜尋
首頁Javajava教程D - 依賴倒置原理(DIP)

D - Dependency Inversion Principle(DIP)

在理解 DIP(依賴倒置原理)之前,了解什麼是高階和低階模組以及抽象非常重要。

高階模組:

高階模組是指應用程式中管理核心功能或業務邏輯的部分。這些模組通常處理應用程式更大、更關鍵的功能。高階模組通常執行更廣泛和更複雜的任務,並且它們可能依賴其他模組來完成工作。

例如,如果您正在建立電子商務應用程序,則訂單管理系統將是一個高級模組。它處理主要任務,例如接受訂單、處理訂單、管理交付等等。

低階模組:

另一方面,低階模組負責特定的和較小的任務。這些模組在應用程式的基礎層級上運作,並執行更詳細的工作,例如在資料庫中儲存資料、配置網路設定等。低階模組通常幫助高階模組執行其任務。

繼續電子商務範例,支付網關整合將是一個低階模組。它的工作專門處理付款,與訂單管理系統的更廣泛功能相比,這是一項更專業的任務。

抽象:

簡單來說,抽像是指系統或過程的一般思想或表示。它定義了應該發生什麼,但沒有指定它將如何發生。它專注於基本功能,而不深入研究底層實現細節。

例子:

想像一下你要開車。駕駛汽車的概念(即抽象)包括:

  • 啟動汽車
  • 停車

但是,抽象並未指定這些操作將如何執行。它不會告訴您它是什麼類型的汽車,它有什麼樣的發動機,或使汽車啟動或停止的具體機制。它僅提供需要做什麼的整體思路。

軟體設計中的抽象:

在軟體設計中,抽象意味著使用定義一組規則或操作的介面或抽象類別來建立通用契約或結構,但這些操作的具體實作是分開的。這允許您定義需要做什麼,而不指定如何完成。

例子:

您可以有一個 PaymentInterface 來聲明處理付款的方法。此介面指定必須處理付款,但沒有定義如何處理付款。這可以透過不同的實現方式來完成,例如 PayPal、Stripe 或其他付款方式。

本質上,抽象著重於通用功能,同時使實作靈活,以便將來更容易更改或擴展。

什麼是依賴倒置原則(DIP)?

根據依賴倒置原則(DIP),高層模組不應該直接依賴低層模組。相反,兩者都應該依賴抽象,例如介面或抽象類別。這使得高層和低層模組可以相互獨立工作,使系統更加靈活並減少變更的影響。

簡化說明:

想像一下您有一個具有多種功能的應用程式。如果一個功能直接依賴另一個功能,那麼修改一個功能將需要更改程式碼的許多部分。 DIP 建議您應該透過通用介面或抽象來使應用程式的不同部分運作,而不是直接依賴。這樣,每個模組都可以獨立運行,並且對一項功能的變更對系統其餘部分的影響最小。

DIP的兩個要點:

  • 高階模組不應依賴低階模組。相反,兩者都應該依賴抽象。

  • 應該依賴抽象,而不是具體(具體實作)。

例子:

考慮一個可以同時使用 PayPal 和 Stripe 作為付款方式的付款系統。如果您直接使用 PayPal 或 Stripe,稍後新增新的支付網關將需要在整個應用程式中進行大量程式碼變更。

但是,如果您遵循DIP,您將使用通用的PaymentInterface。 PayPal 和 Stripe 都會實作這個介面。這樣,如果您以後想新增新的支付網關,只需實作現有的介面即可,讓流程變得更加簡單。

透過遵循這項原則,DIP 增強了程式碼的可維護性和靈活性,允許更平滑的調整和擴展,而不會造成重大中斷。

範例1:

讓我們考慮一個需要啟動和停止不同類型車輛的應用程式。您可以建立一個用作抽象的車輛介面。任何車輛都可以實現這個介面來提供自己的功能。

Java 程式碼:

 // Abstraction: Vehicle interface
interface Vehicle {
    void start();
    void stop();
}

// Car class implements Vehicle interface
class Car implements Vehicle {
    public void start() {
        System.out.println("Car started");
    }

    public void stop() {
        System.out.println("Car stopped");
    }
}

// Bike class implements Vehicle interface
class Bike implements Vehicle {
    public void start() {
        System.out.println("Bike started");
    }

    public void stop() {
        System.out.println("Bike stopped");
    }
}

// Main class
public class Main {
    public static void main(String[] args) {
        Vehicle car = new Car(); // Car as Vehicle
        car.start();
        car.stop();

        Vehicle bike = new Bike(); // Bike as Vehicle
        bike.start();
        bike.stop();
    }
}


解釋:

在這裡,Vehicle 作為一個抽象,指定需要執行哪些操作(即啟動和停止),但它沒有定義這些操作應該如何執行。 Car 和 Bike 類別根據自己的邏輯實作這些方法。這種設計允許輕鬆添加新的車輛類型,例如卡車,而無需更改現有代碼。

新增車輛:卡車
要新增車輛,您只需建立一個實作 Vehicle 介面的 Truck 類,並提供自己的 start() 和 stop() 方法的實作。

卡車的 Java 程式碼:


class Truck implements Vehicle {
    public void start() {
        System.out.println("Truck started");
    }
    public void stop() {
        System.out.println("Truck stopped");
    }
}


在主類別中使用卡車而不進行任何更改:
現在,要將 Truck 包含在 Main 類別中,您可以建立 Truck 的實例並將其用作車輛。 Main 類別或程式碼的任何其他部分無需進行​​任何更改。

主類別的Java程式碼:


<p>public class Main {<br>
    public static void main(String[] args) {<br>
        Vehicle car = new Car(); // Car as Vehicle<br>
        car.start();<br>
        car.stop();</p>
<div class="highlight js-code-highlight">
<pre class='brush:php;toolbar:false;'>    Vehicle bike = new Bike(); // Bike as Vehicle
    bike.start();
    bike.stop();

    // Adding Truck
    Vehicle truck = new Truck(); // Truck as Vehicle
    truck.start();
    truck.stop();
}

}

輸出:
複製程式碼
車子啟動了
車停了
自行車開始了
自行車停了
卡車啟動了
卡車停了

進入全螢幕模式 退出全螢幕模式




Explanation:

Here, the Truck has been added without making any changes to the existing code. The Truck class simply implements its own versions of the start() and stop() functions according to the Vehicle interface. There was no need to modify the Main class or any other part of the application. This demonstrates how the Dependency Inversion Principle (DIP) promotes flexibility and maintainability in code.

Benefits of DIP:

By adhering to the Dependency Inversion Principle, the system remains extensible and maintainable through the use of abstractions.

Importance of DIP:

In this context, Car, Bike, and Truck do not depend directly on the Main class. Instead, the Main class relies solely on the Vehicle abstraction. This means that if a new vehicle type is introduced, there is no need to make changes to the Main class. As a result, the code is much easier to maintain, and adaptability is significantly enhanced.

This approach not only reduces the risk of introducing bugs during modifications but also encourages better design practices by promoting loose coupling between components.

Example 2:

Let's say you want to create a notification system that can send different types of notifications, such as Email, SMS, or Push Notifications. If you directly rely on the Email or SMS classes, adding a new notification method would require changes throughout your code, violating the Dependency Inversion Principle (DIP).

Solution:

We will create an abstraction called Notifier, which will only specify what needs to be done (send notification) without defining how to do it. Different notifier classes (Email, SMS, Push) will implement this functionality in their own way.

JavaScript Code:

<br>
 // Abstraction: Notifier<br>
class Notifier {<br>
    sendNotification(message) {<br>
        throw new Error("Method not implemented.");<br>
    }<br>
}

<p>// EmailNotifier implements Notifier<br>
class EmailNotifier extends Notifier {<br>
    sendNotification(message) {<br>
        console.log(Sending email: ${message});<br>
    }<br>
}</p>

<p>// SMSNotifier implements Notifier<br>
class SMSNotifier extends Notifier {<br>
    sendNotification(message) {<br>
        console.log(Sending SMS: ${message});<br>
    }<br>
}</p>

<p>// PushNotifier implements Notifier<br>
class PushNotifier extends Notifier {<br>
    sendNotification(message) {<br>
        console.log(Sending Push Notification: ${message});<br>
    }<br>
}</p>

<p>// Usage<br>
function sendAlert(notifier, message) {<br>
    notifier.sendNotification(message);<br>
}</p>

<p>// Test different notifiers<br>
const emailNotifier = new EmailNotifier();<br>
const smsNotifier = new SMSNotifier();<br>
const pushNotifier = new PushNotifier();</p>

<p>sendAlert(emailNotifier, "Server is down!");  // Sending email<br>
sendAlert(smsNotifier, "Server is down!");  // Sending SMS<br>
sendAlert(pushNotifier,"Server is down!"); // Sending Push Notification</p>




Explanation:

Why DIP is Important Here:

To add a new notification method (like WhatsApp), we simply need to create a new class that implements Notifier, and the rest of the code will remain unchanged.

Example 3:

Let’s say you are creating an e-commerce site where payments need to be processed using various payment gateways (like PayPal and Stripe). If you directly rely on PayPal or Stripe, making changes or adding a new gateway would require significant alterations to your code, violating the Dependency Inversion Principle (DIP).

Solution:

We will create an abstraction called PaymentGateway. Any payment gateway will operate according to this abstraction, so adding a new gateway will not require changes to other parts of the code.

JavaScript Code:

<br>
 // Abstraction: PaymentGateway<br>
class PaymentGateway {<br>
    processPayment(amount) {<br>
        throw new Error("Method not implemented.");<br>
    }<br>
}

<p>// PayPal class implements PaymentGateway<br>
class PayPal extends PaymentGateway {<br>
    processPayment(amount) {<br>
        console.log(Processing $${amount} payment through PayPal);<br>
    }<br>
}</p>

<p>// Stripe class implements PaymentGateway<br>
class Stripe extends PaymentGateway {<br>
    processPayment(amount) {<br>
        console.log(Processing $${amount} payment through Stripe);<br>
    }<br>
}</p>

<p>// Usage<br>
function processOrder(paymentGateway, amount) {<br>
    paymentGateway.processPayment(amount);<br>
}</p>

<p>// Test different payment gateways<br>
const paypal = new PayPal();<br>
const stripe = new Stripe();</p>

<p>processOrder(paypal, 100);  // Processing $100 payment through PayPal<br>
processOrder(stripe, 200);  // Processing $200 payment through Stripe</p>




Explanation:

DIP is Important Here:

If you need to add a new payment gateway, you simply create a new class that implements the PaymentGateway, and there will be no changes to the core code. This makes the code more maintainable and flexible.

DIP কেন গুরুত্বপূর্ণ?

1. Maintainability: নতুন কিছু যোগ করতে বা পরিবর্তন করতে হলে বড় কোড পরিবর্তন করতে হয় না। DIP মেনে abstraction ব্যবহার করে সিস্টেমকে সহজে মেইনটেইন করা যায়।

2. Flexibility: নতুন ফিচার যোগ করা অনেক সহজ হয়ে যায় কারণ high-level module এবং low-level module আলাদা থাকে।

3. Scalability: DIP এর মাধ্যমে সিস্টেমে নতুন ফিচার বা ফাংশনালিটি যোগ করা সহজ এবং দ্রুত করা যায়।

4. Decoupling: High-level module এবং low-level module সরাসরি একে অপরের উপর নির্ভর না করে abstraction এর মাধ্যমে কাজ করে, যা সিস্টেমের dependencies কমিয়ে দেয়।

Dependency Inversion Principle(DIP) in React

The Dependency Inversion Principle (DIP) can make React applications more modular and maintainable. The core idea of DIP is that high-level components should not depend on low-level components or specific implementations; instead, they should work with a common rule or structure (abstraction).

To implement this concept in React, we typically use props, context, or custom hooks. As a result, components are not directly tied to specific data or logic but operate through abstractions, which facilitates easier changes or the addition of new features in the future.

Example:

By adhering to DIP, your components remain reusable, flexible, and maintainable.

Example 1: Authentication Service

You are building a React application where users need to log in using various authentication services (like Firebase and Auth0). If you directly work with Firebase or Auth0, changing the service would require significant code modifications.

Solution:

By using the AuthService abstraction and adhering to the Dependency Inversion Principle (DIP), you can create an authentication system that allows different authentication services to work together.

JSX Code:

<br>
 import React, { createContext, useContext } from "react";

<p>// Abstraction: AuthService<br>
const AuthServiceContext = createContext();</p>

<p>// FirebaseAuth implementation<br>
const firebaseAuth = {<br>
  login: (username, password) => {<br>
    console.log(Logging in ${username} using Firebase);<br>
  },<br>
  logout: () => {<br>
    console.log("Logging out from Firebase");<br>
  }<br>
};</p>

<p>// Auth0 implementation<br>
const auth0Auth = {<br>
  login: (username, password) => {<br>
    console.log(Logging in ${username} using Auth0);<br>
  },<br>
  logout: () => {<br>
    console.log("Logging out from Auth0");<br>
  }<br>
};</p>

<p>// AuthProvider component for dependency injection<br>
const AuthProvider = ({ children, authService }) => {<br>
  return (<br>
    <authservicecontext.provider value="{authService}"><br>
      {children}<br>
    </authservicecontext.provider><br>
  );<br>
};</p>

<p>// Custom hook to access the AuthService<br>
const useAuthService = () => {<br>
  return useContext(AuthServiceContext);<br>
};</p>

<p>// Login component that depends on abstraction<br>
const Login = () => {<br>
  const authService = useAuthService();</p>

<p>const handleLogin = () => {<br>
    authService.login("username", "password");<br>
  };</p>

<p>return <button onclick="{handleLogin}">Login</button>;<br>
};</p>

<p>// App component<br>
const App = () => {<br>
  return (<br>
    <authprovider authservice="{firebaseAuth}"><br>
      <login></login><br>
    </authprovider><br>
  );<br>
};</p>

<p>export default App;</p>




Explanation:

This design pattern adheres to the Dependency Inversion Principle (DIP), promoting flexibility and maintainability in the application.

Example 2: API Service Layer with Functional Components

You are making various API calls using fetch or Axios. If you work directly with fetch or Axios, changing the API service would require numerous code changes.

Solution:

We will create an abstraction called ApiService, which will adhere to the Dependency Inversion Principle (DIP) for making API calls. This way, if the service changes, the components will remain unchanged.

JSX Code:

<br>
 import React, { createContext, useContext } from "react";

<p>// Abstraction: ApiService<br>
const ApiServiceContext = createContext();</p>

<p>// Fetch API implementation<br>
const fetchApiService = {<br>
  get: async (url) => {<br>
    const response = await fetch(url);<br>
    return response.json();<br>
  },<br>
  post: async (url, data) => {<br>
    const response = await fetch(url, {<br>
      method: "POST",<br>
      body: JSON.stringify(data),<br>
      headers: { "Content-Type": "application/json" }<br>
    });<br>
    return response.json();<br>
  }<br>
};</p>

<p>// Axios API implementation (for example purposes, similar API interface)<br>
const axiosApiService = {<br>
  get: async (url) => {<br>
    const response = await axios.get(url);<br>
    return response.data;<br>
  },<br>
  post: async (url, data) => {<br>
    const response = await axios.post(url, data);<br>
    return response.data;<br>
  }<br>
};</p>

<p>// ApiProvider for injecting the service<br>
const ApiProvider = ({ children, apiService }) => {<br>
  return (<br>
    <apiservicecontext.provider value="{apiService}"><br>
      {children}<br>
    </apiservicecontext.provider><br>
  );<br>
};</p>

<p>// Custom hook to use the ApiService<br>
const useApiService = () => {<br>
  return useContext(ApiServiceContext);<br>
};</p>

<p>// Component using ApiService abstraction<br>
const DataFetcher = () => {<br>
  const apiService = useApiService();</p>

<p>const fetchData = async () => {<br>
    const data = await apiService.get("https://jsonplaceholder.typicode.com/todos");<br>
    console.log(data);<br>
  };</p>

<p>return <button onclick="{fetchData}">Fetch Data</button>;<br>
};</p>

<p>// App component<br>
const App = () => {<br>
  return (<br>
    <apiprovider apiservice="{fetchApiService}"><br>
      <datafetcher></datafetcher><br>
    </apiprovider><br>
  );<br>
};</p>

<p>export default App;</p>




Explanation:

Example 3: Form Validation with Functional Components

You have created a React app where form validation is required. If you write the validation logic directly inside the component, any changes to the validation logic would require modifications throughout the code.

Solution:

We will create an abstraction called FormValidator. Different validation libraries (such as Yup or custom validation) will work according to this abstraction.

JSX Code:

<br>
 import React from "react";

<p>// Abstraction: FormValidator<br>
const FormValidatorContext = React.createContext();</p>

<p>// Yup validator implementation<br>
const yupValidator = {<br>
  validate: (formData) => {<br>
    console.log("Validating using Yup");<br>
    return true; // Dummy validation<br>
  }<br>
};</p>

<p>// Custom validator implementation<br>
const customValidator = {<br>
  validate: (formData) => {<br>
    console.log("Validating using custom logic");<br>
    return true; // Dummy validation<br>
  }<br>
};</p>

<p>// FormValidatorProvider for injecting the service<br>
const FormValidatorProvider = ({ children, validatorService }) => {<br>
  return (<br>
    <formvalidatorcontext.provider value="{validatorService}"><br>
      {children}<br>
    </formvalidatorcontext.provider><br>
  );<br>
};</p>

<p>// Custom hook to use the FormValidator<br>
const useFormValidator = () => {<br>
  return React.useContext(FormValidatorContext);<br>
};</p>

<p>// Form component using FormValidator abstraction<br>
const Form = () => {<br>
  const validator = useFormValidator();</p>

<p>const handleSubmit = () => {<br>
    const formData = { name: "John Doe" };<br>
    const isValid = validator.validate(formData);<br>
    console.log("Is form valid?", isValid);<br>
  };</p>

<p>return <button onclick="{handleSubmit}">Submit</button>;<br>
};</p>

<p>// App component<br>
const App = () => {<br>
  return (<br>
    <formvalidatorprovider validatorservice="{yupValidator}"><br>
      <form></form>
<br>
    </formvalidatorprovider><br>
  );<br>
};</p>

<p>export default App;</p>




Explanation:

Disadvantages of Dependency Inversion Principle (DIP):

While the Dependency Inversion Principle (DIP) is a highly beneficial design principle, it also comes with some limitations or disadvantages. Below are some of the key drawbacks of using DIP:

1. Increased Complexity: Following DIP requires creating additional interfaces or abstract classes. This increases the structure's complexity, especially in smaller projects. Directly using low-level modules makes the code simpler, but adhering to DIP requires introducing multiple abstractions, which can add complexity.

2. Overhead of Managing Dependencies: Since high-level and low-level modules are not directly connected, additional design patterns like dependency injection or context are needed to manage dependencies. This increases the maintenance overhead of the project.

3. Unnecessary for Small Projects: In smaller projects or in cases with fewer dependencies or low complexity, using DIP can be unnecessary. Implementing DIP creates additional abstractions that make the code more complicated, while directly using low-level modules can be simpler and more effective.

4. Performance Overhead: By introducing abstractions between high-level and low-level modules, there can be some performance overhead, especially if there are many abstraction layers. Each abstraction adds extra processing, which can slightly impact performance.

5. Misuse of Abstraction: Excessive or incorrect use of abstraction can reduce the readability and maintainability of the code. If abstractions are not thoughtfully implemented, they can create more disadvantages than the intended benefits of DIP.

6. Harder to Debug: Due to the use of abstractions and interfaces, debugging can become more challenging. Without directly working with the implementation, identifying where a problem originates from can take more time.

7. Dependency Injection Tools Required: Implementing DIP often requires using dependency injection frameworks or tools, which take time and effort to learn. Additionally, the use of these frameworks increases the complexity of the project.

Conclusion:

Although DIP is a powerful and beneficial principle, it does have its limitations. In smaller projects or less complex contexts, adhering to DIP may be unnecessary. Therefore, proper analysis is needed to determine when and where to apply this principle for the best results.

? Connect with me on LinkedIn:

I regularly share insights on JavaScript, Node.js, React, Next.js, software engineering, data structures, algorithms, and more. Let’s connect, learn, and grow together!

Follow me: Nozibul Islam

以上是D - 依賴倒置原理(DIP)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

如何在Java中實施功能編程技術?如何在Java中實施功能編程技術?Mar 11, 2025 pm 05:51 PM

本文使用lambda表達式,流API,方法參考和可選探索將功能編程集成到Java中。 它突出顯示了通過簡潔性和不變性改善代碼可讀性和可維護性等好處

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何將Java的Nio(新輸入/輸出)API用於非阻滯I/O?如何將Java的Nio(新輸入/輸出)API用於非阻滯I/O?Mar 11, 2025 pm 05:51 PM

本文使用選擇器和頻道使用單個線程有效地處理多個連接的Java的NIO API,用於非阻滯I/O。 它詳細介紹了過程,好處(可伸縮性,性能)和潛在的陷阱(複雜性,

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用Java的插座API進行網絡通信?如何使用Java的插座API進行網絡通信?Mar 11, 2025 pm 05:53 PM

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能