Skip to content

Instantly share code, notes, and snippets.

@yamamaya
Created February 20, 2026 12:18
Show Gist options
  • Select an option

  • Save yamamaya/5c93007175fcf0cebd5e6d831fd3e3ee to your computer and use it in GitHub Desktop.

Select an option

Save yamamaya/5c93007175fcf0cebd5e6d831fd3e3ee to your computer and use it in GitHub Desktop.
DIの練習・HTTPクライアントの実装
using System.Net.Sockets;
using System.Text;
// DIの練習として、HTTPクライアントを実装する。
// DI(Dependency Injection)とは、クラスが必要とする依存関係を外部から注入することで、クラスの柔軟性とテスト容易性を向上させる設計パターンである。
// この例では、WebFetcherクラスがHTTPプロトコルを使用してウェブページを取得するための依存関係を注入する。
// WebFetcherはIProtocolに依存しているが、具体的なプロトコルの実装には依存していない。
// 更に、Http11ProtocolはITransportに依存しているが、具体的なトランスポートの実装には依存していない。
// これにより、具体的な実装との結合度が低くなり、柔軟性とテスト容易性が向上する。
namespace DI_practice1_http {
internal class Program {
static void Main( string[] args ) {
// 依存関係の構築
// TcpTransportを作成
var transport = new TcpTransport();
// TcpTransportを注入してHttp11Protocolを作成
var protocol = new Http11Protocol( transport );
// Http11Protocolを注入してWebFetcherを作成
var fetcher = new WebFetcher( protocol );
// WebFetcherを使用してexample.comのトップページを取得
fetcher.Fetch( "example.com", "/" );
}
}
/// <summary>
/// ホストとパスを指定してウェブページを取得するクラス
/// </summary>
/// <remarks>
/// WebFetcherはプロトコル層に依存しているが、具体的な実装には依存していない
/// </remarks>
class WebFetcher {
private readonly IProtocol _protocol;
/// <summary>
/// WebFetcherのコンストラクタ
/// </summary>
/// <remarks>
/// IProtocolを注入する
/// </remarks>
/// <param name="protocol"></param>
public WebFetcher( IProtocol protocol ) {
_protocol = protocol;
}
public void Fetch( string host, string path ) {
var response = _protocol.Request( host, path );
Console.Write( response );
}
}
/// <summary>
/// プロトコル層の契約
/// </summary>
interface IProtocol {
/// <summary>
/// ホストとパスを指定してリクエストを送信し、レスポンスを文字列で返す
/// </summary>
/// <param name="host"></param>
/// <param name="path"></param>
/// <returns></returns>
string Request( string host, string path );
}
/// <summary>
/// HTTP/1.1の実装
/// </summary>
/// <remarks>
/// Http11ProtocolはIProtocolに依存しているが、具体的なトランスポートの実装には依存していない
/// </remarks>
class Http11Protocol : IProtocol {
private readonly ITransport _transport;
/// <summary>
/// Http11Protocolのコンストラクタ
/// </summary>
/// <remarks>
/// ITransportを注入する
/// </remarks>
/// <param name="transport"></param>
public Http11Protocol( ITransport transport ) {
_transport = transport;
}
/// <summary>
/// Requestの実装
/// </summary>
/// <param name="host"></param>
/// <param name="path"></param>
/// <returns></returns>
public string Request( string host, string path ) {
var stream = _transport.Connect( host, 80 );
var request = $"GET {path} HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n";
stream.Write( Encoding.ASCII.GetBytes( request ) );
var sb = new StringBuilder();
var buffer = new byte[ 4096 ];
int bytesRead;
while ( ( bytesRead = stream.Read( buffer, 0, buffer.Length ) ) > 0 ) {
sb.Append( Encoding.ASCII.GetString( buffer, 0, bytesRead ) );
}
return sb.ToString();
}
}
/// <summary>
/// トランスポート層の契約
/// </summary>
interface ITransport {
/// <summary>
/// ホストとポートを指定して接続し、ストリームを返す
/// </summary>
/// <param name="host"></param>
/// <param name="port"></param>
/// <returns></returns>
Stream Connect( string host, int port );
}
/// <summary>
/// TCPを使用したトランスポートの実装
/// </summary>
class TcpTransport : ITransport {
/// <summary>
/// Connectの実装
/// </summary>
/// <param name="host"></param>
/// <param name="port"></param>
/// <returns></returns>
public Stream Connect( string host, int port ) {
var client = new TcpClient( host, port );
return client.GetStream();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment