Skip to content

第14章 インターフェイス

この章では、オブジェクト指向プログラミングで重要な インターフェイス を学習します。

第13章では、継承とポリモーフィズムを学習しました。

継承では、親クラスに共通部分をまとめ、子クラスがそれを受け継ぎました。

abstract class EmployeeBase
{
public abstract int GetPaymentAmount();
}
class RegularEmployee : EmployeeBase
{
public override int GetPaymentAmount()
{
return MonthlySalary;
}
}

インターフェイスも、ポリモーフィズムに関係する仕組みです。

ただし、インターフェイスは、親クラスのように共通のデータを持つというよりも、そのクラスが持つべき機能の約束を表します。

たとえば、次のような約束を作ることができます。

印刷できる
保存できる
検索できる
支給額を計算できる
一覧を取得できる

C#では、このような「できること」をインターフェイスとして定義できます。

この章では、次のように考えていきます。

インターフェイス
→ クラスに対して「このメソッドを持っていてください」と約束するもの
クラス
→ インターフェイスで決められたメソッドを実装するもの

この章でできるようになること

Section titled “この章でできるようになること”

この章を終えると、次のことができるようになります。

  • インターフェイスとは何かをおおまかに説明できる
  • インターフェイスは「機能の約束」であることを説明できる
  • interface を使ってインターフェイスを定義できる
  • クラスでインターフェイスを実装できる
  • インターフェイスにメソッドを定義できる
  • インターフェイスにプロパティを定義できる
  • インターフェイス型の変数に、実装クラスのオブジェクトを代入できる
  • List<インターフェイス> で複数のクラスをまとめて扱える
  • 抽象クラスとインターフェイスの違いをおおまかに説明できる
  • WebアプリやDB接続でよく出てくる ServiceRepository の考え方に少し慣れる

項目内容
開発環境Visual Studio 2022
プロジェクト種類コンソール アプリ
対象フレームワーク.NET 8
プロジェクト名Chapter14_Interface

作業を始める前に、次の内容を確認してください。

  • クラスを作成できる
  • プロパティを定義できる
  • メソッドを定義できる
  • 継承の基本を説明できる
  • 抽象クラスの基本を説明できる
  • List<T> を使える
  • foreach 文を使える
  • 第13章の内容をGitに提出済みである

インターフェイスは、クラスが持つべき機能を決めるための仕組みです。

たとえば、「印刷できる」という機能を考えます。

印刷できるもの
→ Print メソッドを持っている

この約束をインターフェイスとして表すと、次のようになります。

interface IPrintable
{
void Print();
}

IPrintable は、「印刷できるもの」を表すインターフェイスです。

このインターフェイスを実装するクラスは、必ず Print メソッドを持つ必要があります。


C#では、インターフェイス名の先頭に I を付けることが多いです。

例:

IPrintable
ISearchable
IPayable
IEmployeeRepository

I は Interface の頭文字です。

必ずではありませんが、現場のC#コードでは非常によく使われる命名です。


Employee クラスで IPrintable を実装してみます。

using System;
class Program
{
static void Main()
{
Employee employee = new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
};
employee.Print();
}
}
interface IPrintable
{
void Print();
}
class Employee : IPrintable
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}
}

実行結果:

社員ID:1001
氏名:山田太郎
部署:営業部

次の部分に注目してください。

class Employee : IPrintable

これは、Employee クラスが IPrintable インターフェイスを実装していることを表します。

インターフェイスを実装したクラスは、インターフェイスで定義されたメソッドを必ず持つ必要があります。

public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}

もし Print メソッドを書かなければ、コンパイルエラーになります。


インターフェイス自体には処理を書かない

Section titled “インターフェイス自体には処理を書かない”

この章では、インターフェイスは次のように書くものとして扱います。

interface IPrintable
{
void Print();
}

Print メソッドの中身は書きません。

処理の中身は、インターフェイスを実装するクラス側に書きます。

class Employee : IPrintable
{
public void Print()
{
Console.WriteLine("社員情報を表示します。");
}
}

補足

新しいC#では、インターフェイスに既定の実装を書ける機能もあります。 ただし、初学者向けの本研修では、まず「インターフェイスは約束だけを書くもの」として理解します。


14-2 インターフェイス型として扱う

Section titled “14-2 インターフェイス型として扱う”

インターフェイスを実装したクラスのオブジェクトは、インターフェイス型の変数に代入できます。

IPrintable printable = new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
};

この場合、printableIPrintable 型として扱われます。

つまり、IPrintable に定義されている Print メソッドを呼び出せます。


インターフェイス型でPrintを呼び出す

Section titled “インターフェイス型でPrintを呼び出す”
using System;
class Program
{
static void Main()
{
IPrintable printable = new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
};
printable.Print();
}
}
interface IPrintable
{
void Print();
}
class Employee : IPrintable
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}
}

実行結果:

社員ID:1001
氏名:山田太郎
部署:営業部

インターフェイス型では約束された機能だけ使える

Section titled “インターフェイス型では約束された機能だけ使える”

次のコードでは、printableIPrintable 型です。

IPrintable printable = new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
};

この場合、Print メソッドは呼び出せます。

printable.Print();

しかし、次のように EmployeeName を直接参照しようとするとエラーになります。

Console.WriteLine(printable.EmployeeName);

Employee クラスには EmployeeName がありますが、IPrintable インターフェイスには EmployeeName が定義されていないからです。

このように、インターフェイス型として扱う場合、そのインターフェイスで約束されたメンバーだけを利用できます。


インターフェイスにプロパティを定義する

Section titled “インターフェイスにプロパティを定義する”

インターフェイスには、メソッドだけでなくプロパティも定義できます。

interface IPrintable
{
string Title { get; }
void Print();
}

この場合、実装クラスは Title プロパティと Print メソッドを持つ必要があります。

using System;
class Program
{
static void Main()
{
IPrintable report = new SalesReport();
Console.WriteLine(report.Title);
report.Print();
}
}
interface IPrintable
{
string Title { get; }
void Print();
}
class SalesReport : IPrintable
{
public string Title
{
get
{
return "売上レポート";
}
}
public void Print()
{
Console.WriteLine("売上レポートを出力します。");
}
}

実行結果:

売上レポート
売上レポートを出力します。

14-3 複数のクラスを同じインターフェイスで扱う

Section titled “14-3 複数のクラスを同じインターフェイスで扱う”

別々のクラスに同じ機能を持たせる

Section titled “別々のクラスに同じ機能を持たせる”

インターフェイスの大きなメリットは、別々のクラスを同じ機能でまとめて扱えることです。

たとえば、次の2つのクラスを考えます。

Employee
→ 社員情報を印刷できる
SalesReport
→ 売上レポートを印刷できる

この2つは、同じ種類のクラスではありません。

しかし、どちらも「印刷できる」という機能を持っています。

そこで、どちらにも IPrintable を実装させます。


EmployeeとSalesReportにIPrintableを実装する

Section titled “EmployeeとSalesReportにIPrintableを実装する”
using System;
class Program
{
static void Main()
{
Employee employee = new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
};
SalesReport report = new SalesReport
{
ReportDate = new DateTime(2026, 5, 18),
TotalAmount = 1200000
};
employee.Print();
report.Print();
}
}
interface IPrintable
{
void Print();
}
class Employee : IPrintable
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}
}
class SalesReport : IPrintable
{
public DateTime ReportDate { get; set; }
public int TotalAmount { get; set; }
public void Print()
{
Console.WriteLine($"売上日:{ReportDate.ToString("yyyy/MM/dd")}");
Console.WriteLine($"売上合計:{TotalAmount}");
}
}

実行結果:

社員ID:1001
氏名:山田太郎
部署:営業部
売上日:2026/05/18
売上合計:1200000円

EmployeeSalesReport は別々のクラスですが、どちらも IPrintable を実装しています。

そのため、List<IPrintable> にまとめることができます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<IPrintable> printTargets = new List<IPrintable>
{
new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部"
},
new SalesReport
{
ReportDate = new DateTime(2026, 5, 18),
TotalAmount = 1200000
}
};
foreach (IPrintable printTarget in printTargets)
{
printTarget.Print();
}
}
}
interface IPrintable
{
void Print();
}
class Employee : IPrintable
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}
}
class SalesReport : IPrintable
{
public DateTime ReportDate { get; set; }
public int TotalAmount { get; set; }
public void Print()
{
Console.WriteLine($"売上日:{ReportDate.ToString("yyyy/MM/dd")}");
Console.WriteLine($"売上合計:{TotalAmount}");
}
}

実行結果:

社員ID:1001
氏名:山田太郎
部署:営業部
売上日:2026/05/18
売上合計:1200000円

foreach の中では、すべて IPrintable として扱っています。

foreach (IPrintable printTarget in printTargets)
{
printTarget.Print();
}

実際のオブジェクトが Employee なら社員情報の印刷、SalesReport なら売上レポートの印刷が実行されます。

これもポリモーフィズムの一種です。


14-4 インターフェイスとポリモーフィズム

Section titled “14-4 インターフェイスとポリモーフィズム”

同じ呼び出し方で異なる処理を実行する

Section titled “同じ呼び出し方で異なる処理を実行する”

第13章では、親クラス型を使ってポリモーフィズムを学びました。

List<EmployeeBase> employees = new List<EmployeeBase>
{
new RegularEmployee(...),
new ContractEmployee(...)
};

インターフェイスでも、同じようにポリモーフィズムを実現できます。

List<IPrintable> printTargets = new List<IPrintable>
{
new Employee(),
new SalesReport()
};

呼び出し側は、具体的なクラスを気にせず、インターフェイスで約束されたメソッドを呼び出します。

foreach (IPrintable printTarget in printTargets)
{
printTarget.Print();
}

次は、支給額を計算できることを表す IPayable インターフェイスを作ります。

interface IPayable
{
int GetPaymentAmount();
}

IPayable を実装するクラスは、必ず GetPaymentAmount メソッドを持つ必要があります。


正社員と契約社員にIPayableを実装する

Section titled “正社員と契約社員にIPayableを実装する”
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<IPayable> payTargets = new List<IPayable>
{
new RegularEmployee
{
EmployeeName = "山田太郎",
MonthlySalary = 300000
},
new ContractEmployee
{
EmployeeName = "佐藤花子",
HourlyWage = 1800,
WorkHours = 120
}
};
foreach (IPayable payTarget in payTargets)
{
Console.WriteLine($"支給額:{payTarget.GetPaymentAmount()}");
}
}
}
interface IPayable
{
int GetPaymentAmount();
}
class RegularEmployee : IPayable
{
public string EmployeeName { get; set; } = "";
public int MonthlySalary { get; set; }
public int GetPaymentAmount()
{
return MonthlySalary;
}
}
class ContractEmployee : IPayable
{
public string EmployeeName { get; set; } = "";
public int HourlyWage { get; set; }
public int WorkHours { get; set; }
public int GetPaymentAmount()
{
return HourlyWage * WorkHours;
}
}

実行結果:

支給額:300000円
支給額:216000円

RegularEmployeeContractEmployee は、どちらも IPayable を実装しています。

そのため、List<IPayable> にまとめられます。


インターフェイス型で扱うと使える範囲が限定される

Section titled “インターフェイス型で扱うと使える範囲が限定される”

先ほどのコードでは、payTargetIPayable 型です。

foreach (IPayable payTarget in payTargets)
{
Console.WriteLine($"支給額:{payTarget.GetPaymentAmount()}");
}

そのため、GetPaymentAmount は呼び出せます。

しかし、次のように EmployeeName を参照することはできません。

Console.WriteLine(payTarget.EmployeeName);

EmployeeNameRegularEmployeeContractEmployee にはありますが、IPayable には定義されていないからです。

インターフェイス型で扱う場合は、インターフェイスに定義された機能だけが使えることに注意してください。


14-5 複数のインターフェイスを実装する

Section titled “14-5 複数のインターフェイスを実装する”

クラスは複数のインターフェイスを実装できる

Section titled “クラスは複数のインターフェイスを実装できる”

C#では、1つのクラスが複数のインターフェイスを実装できます。

たとえば、社員クラスに次の2つの機能を持たせることを考えます。

印刷できる
支給額を計算できる

この場合、Employee クラスは IPrintableIPayable の両方を実装できます。

class RegularEmployee : IPrintable, IPayable
{
}

複数のインターフェイスを実装する場合は、カンマで区切ります。


using System;
class Program
{
static void Main()
{
RegularEmployee employee = new RegularEmployee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "営業部",
MonthlySalary = 300000
};
employee.Print();
int paymentAmount = employee.GetPaymentAmount();
Console.WriteLine($"支給額:{paymentAmount}");
}
}
interface IPrintable
{
void Print();
}
interface IPayable
{
int GetPaymentAmount();
}
class RegularEmployee : IPrintable, IPayable
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int MonthlySalary { get; set; }
public void Print()
{
Console.WriteLine($"社員ID:{EmployeeId}");
Console.WriteLine($"氏名:{EmployeeName}");
Console.WriteLine($"部署:{DepartmentName}");
}
public int GetPaymentAmount()
{
return MonthlySalary;
}
}

実行結果:

社員ID:1001
氏名:山田太郎
部署:営業部
支給額:300000円

継承とインターフェイスを組み合わせる

Section titled “継承とインターフェイスを組み合わせる”

C#では、クラスの継承は基本的に1つだけです。

class RegularEmployee : EmployeeBase
{
}

しかし、インターフェイスは複数実装できます。

class RegularEmployee : EmployeeBase, IPrintable, IPayable
{
}

この場合、最初に親クラスを書き、その後にインターフェイスを書きます。

class 子クラス : 親クラス, インターフェイス1, インターフェイス2
{
}

この章では、まず次のように覚えておきましょう。

クラスの継承
→ 基本的に1つ
インターフェイスの実装
→ 複数可能

14-6 抽象クラスとインターフェイスの違い

Section titled “14-6 抽象クラスとインターフェイスの違い”

どちらも共通の型として扱える

Section titled “どちらも共通の型として扱える”

抽象クラスとインターフェイスは、どちらもポリモーフィズムに使えます。

抽象クラスの例:

abstract class EmployeeBase
{
public abstract int GetPaymentAmount();
}

インターフェイスの例:

interface IPayable
{
int GetPaymentAmount();
}

どちらも、共通のメソッドを呼び出すために使えます。


抽象クラスは、共通のプロパティや処理を持たせたい場合に向いています。

abstract class EmployeeBase
{
public int EmployeeId { get; private set; }
public string EmployeeName { get; private set; }
public EmployeeBase(int employeeId, string employeeName)
{
EmployeeId = employeeId;
EmployeeName = employeeName;
}
public abstract int GetPaymentAmount();
}

このように、社員IDや氏名のような共通情報を持たせられます。


インターフェイスは「機能の約束」

Section titled “インターフェイスは「機能の約束」”

インターフェイスは、共通のデータというよりも、持っている機能を表すのに向いています。

interface IPrintable
{
void Print();
}

IPrintable は、「印刷できる」という機能を表しています。

社員でも、レポートでも、請求書でも、「印刷できる」なら IPrintable を実装できます。


観点抽象クラスインターフェイス
主な役割共通の土台機能の約束
キーワードabstract classinterface
継承・実装1つのクラスのみ継承複数実装できる
共通プロパティ持たせやすい約束として定義できる
共通処理持たせやすい本研修では処理は書かない
向いている例社員の共通情報印刷できる、保存できる、検索できる

初学者の段階では、無理に使い分けを完全に理解する必要はありません。

この章では、次のように考えてください。

共通のデータや処理をまとめたい
→ 抽象クラスが候補
その機能を持っていることを約束したい
→ インターフェイスが候補

現場のコードでは、サービスやリポジトリの設計でインターフェイスが使われることがあります。


14-7 ServiceとRepositoryのイメージ

Section titled “14-7 ServiceとRepositoryのイメージ”

後のWebアプリ・DB接続につながる考え方

Section titled “後のWebアプリ・DB接続につながる考え方”

後の章では、Oracle Databaseから社員情報を取得します。

そのとき、次のようなクラスが登場する可能性があります。

Employee
EmployeeService
EmployeeRepository
EmployeeDao

現場のC#コードでは、これらに対応するインターフェイスが用意されることがあります。

IEmployeeService
IEmployeeRepository

この章では、まだ本格的なDB接続は行いません。

ただし、インターフェイスがどのような場面で使われるのか、簡単なイメージを確認します。


IEmployeeRepository は、社員データを取得する機能の約束を表すインターフェイスです。

interface IEmployeeRepository
{
List<Employee> GetAll();
Employee? FindById(int employeeId);
}

このインターフェイスを実装するクラスは、次の2つのメソッドを持つ必要があります。

GetAll
→ 全社員を取得する
FindById
→ 社員IDで1件検索する

まだDBには接続せず、サンプルデータを返すクラスを作ります。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
IEmployeeRepository repository = new SampleEmployeeRepository();
List<Employee> employees = repository.GetAll();
foreach (Employee employee in employees)
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}");
}
Employee? foundEmployee = repository.FindById(1002);
if (foundEmployee != null)
{
Console.WriteLine($"検索結果:{foundEmployee.EmployeeName}");
}
}
}
interface IEmployeeRepository
{
List<Employee> GetAll();
Employee? FindById(int employeeId);
}
class SampleEmployeeRepository : IEmployeeRepository
{
private List<Employee> _employees = new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎" },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子" },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎" }
};
public List<Employee> GetAll()
{
return _employees;
}
public Employee? FindById(int employeeId)
{
return _employees.FirstOrDefault(employee => employee.EmployeeId == employeeId);
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
}

実行結果:

1001:山田太郎
1002:佐藤花子
1003:鈴木一郎
検索結果:佐藤花子

今は、SampleEmployeeRepository がサンプルデータを返しています。

後のDB接続編では、Oracle Databaseからデータを取得するクラスを作ることになります。

SampleEmployeeRepository
→ サンプルデータを返す
OracleEmployeeRepository
→ Oracle Databaseから取得する

どちらも IEmployeeRepository を実装していれば、呼び出し側は同じように扱えます。

IEmployeeRepository repository = new SampleEmployeeRepository();

将来的には、次のように差し替えるイメージです。

IEmployeeRepository repository = new OracleEmployeeRepository();

このように、インターフェイスを使うと、呼び出し側のコードを大きく変えずに実装を差し替えやすくなります。

補足

Webアプリでは、さらにDIという仕組みを使って、インターフェイスと実装クラスを組み合わせることがあります。 この章では深く扱いませんが、IEmployeeRepository のような名前を見たときに「社員データ取得の約束を表しているのだな」と読めることを目指します。


この章でよくあるつまずきを確認します。

つまずき原因対応
インターフェイスの意味が分からない処理の中身がなく抽象的に見える「機能の約束」と考える
interfaceclass の違いが分からないどちらも型として使えるため混同するclassは実体を作る設計図、interfaceは約束
IPrintableI が分からない命名規則を知らないInterfaceのIと考える
インターフェイスのメソッドに処理を書こうとするクラスのメソッドと混同している本研修ではインターフェイスには中身を書かない
実装クラスでメソッドを書き忘れる約束されたメソッドを実装していないエラー内容を見て不足メソッドを追加する
インターフェイス型でプロパティが使えないインターフェイスに定義されていないインターフェイス型では約束されたメンバーだけ使える
抽象クラスとの違いが分からないどちらもポリモーフィズムに使える抽象クラスは共通の土台、インターフェイスは機能の約束
インターフェイスをどこで使うのか分からない小さなサンプルでは必要性を感じにくい現場ではServiceやRepositoryでよく見ると考える

次の項目について、自分で説明できるか確認してください。

  • インターフェイスとは何かをおおまかに説明できる
  • インターフェイスは「機能の約束」であることを説明できる
  • interface を使ってインターフェイスを定義できる
  • インターフェイス名に I を付ける慣習を説明できる
  • クラスでインターフェイスを実装できる
  • インターフェイスで定義したメソッドをクラス側で実装できる
  • インターフェイス型の変数に実装クラスのオブジェクトを代入できる
  • List<IPrintable> のように、インターフェイス型のリストを使える
  • インターフェイスにプロパティを定義できる
  • 1つのクラスが複数のインターフェイスを実装できることを説明できる
  • 抽象クラスとインターフェイスの違いをおおまかに説明できる
  • IEmployeeRepository のような名前を見たときに、役割を想像できる

研修の進め方によっては、隣の人またはチーム内で説明確認を行います。

次の内容を、自分の言葉で説明してください。

  1. インターフェイスとは何ですか。
  2. IPrintable はどのような役割を持つインターフェイスですか。
  3. class Employee : IPrintable は何を意味していますか。
  4. インターフェイス型の変数では、どのメンバーを使えますか。
  5. List<IPrintable> に異なるクラスのオブジェクトを入れられるのはなぜですか。
  6. 抽象クラスとインターフェイスの違いは何ですか。
  7. IEmployeeRepository はどのような役割を持つと考えられますか。

説明するときは、完全な答えでなくても構いません。
自分の言葉で説明しようとすることが大切です。


この章の演習課題に取り組みます。

制限時間は 80分 です。

時間内にすべて完成しなくても構いません。
できたところまでを保存し、Gitに提出してください。


まずは、全員が必須課題に取り組んでください。


IPrintable インターフェイスを作成し、Employee クラスで実装してください。

仕様:

interface IPrintable
{
void Print();
}

実行結果例:

社員ID:1001
氏名:山田太郎
部署:営業部

条件:

  • interface を使う
  • Employee : IPrintable と書く
  • Employee クラスに Print メソッドを実装する

課題14-2 インターフェイス型の変数を使う

Section titled “課題14-2 インターフェイス型の変数を使う”

課題14-1の Employee オブジェクトを、IPrintable 型の変数に代入し、Print メソッドを呼び出してください。

実行結果例:

社員ID:1001
氏名:山田太郎
部署:営業部

条件:

  • IPrintable printable = new Employee { ... }; のように書く
  • printable.Print(); を呼び出す
  • インターフェイス型では、インターフェイスに定義されたメソッドだけ使えることを確認する

課題14-3 SalesReportにもIPrintableを実装する

Section titled “課題14-3 SalesReportにもIPrintableを実装する”

SalesReport クラスを作成し、IPrintable を実装してください。

プロパティ:

プロパティ名
ReportDateDateTime
TotalAmountint

実行結果例:

売上日:2026/05/18
売上合計:1200000円

条件:

  • SalesReport : IPrintable と書く
  • Print メソッドを実装する
  • 日付は ToString("yyyy/MM/dd") で表示する

課題14-4 Listでまとめて印刷する

Section titled “課題14-4 Listでまとめて印刷する”

EmployeeSalesReportList<IPrintable> に入れ、foreachPrint メソッドを呼び出してください。

条件:

  • List<IPrintable> を使う
  • EmployeeSalesReport を同じリストに入れる
  • foreachPrint を呼び出す
  • 実際のクラスによって表示内容が変わることを確認する

必須課題が終わった人は、発展課題に取り組んでください。


支給額を計算できることを表す IPayable インターフェイスを作成してください。

仕様:

interface IPayable
{
int GetPaymentAmount();
}

RegularEmployeeContractEmployeeIPayable を実装してください。

クラス支給額
RegularEmployee月給
ContractEmployee時給 × 勤務時間

実行結果例:

支給額:300000円
支給額:216000円

条件:

  • IPayable を作成する
  • RegularEmployee : IPayable とする
  • ContractEmployee : IPayable とする
  • List<IPayable> でまとめて処理する

課題14-6 複数のインターフェイスを実装する

Section titled “課題14-6 複数のインターフェイスを実装する”

RegularEmployee クラスに、IPrintableIPayable の両方を実装してください。

実行結果例:

社員ID:1001
氏名:山田太郎
部署:営業部
支給額:300000円

条件:

  • class RegularEmployee : IPrintable, IPayable と書く
  • Print メソッドを実装する
  • GetPaymentAmount メソッドを実装する

課題14-7 IEmployeeRepositoryを作成する

Section titled “課題14-7 IEmployeeRepositoryを作成する”

社員データを取得するための IEmployeeRepository インターフェイスを作成してください。

仕様:

interface IEmployeeRepository
{
List<Employee> GetAll();
Employee? FindById(int employeeId);
}

次に、サンプルデータを返す SampleEmployeeRepository クラスを作成してください。

実行結果例:

1001:山田太郎
1002:佐藤花子
1003:鈴木一郎
検索結果:佐藤花子

条件:

  • IEmployeeRepository を作成する
  • SampleEmployeeRepository : IEmployeeRepository と書く
  • GetAll で全社員を返す
  • FindById で社員ID検索を行う
  • FirstOrDefault を使ってもよい

課題14-8 Repositoryを差し替えるイメージを確認する

Section titled “課題14-8 Repositoryを差し替えるイメージを確認する”

IEmployeeRepository 型の変数に SampleEmployeeRepository を代入して使ってください。

IEmployeeRepository repository = new SampleEmployeeRepository();

その後、コメントとして次の内容を書いてください。

// 後のDB接続編では、ここを OracleEmployeeRepository に差し替えるイメージ
// IEmployeeRepository repository = new OracleEmployeeRepository();

条件:

  • インターフェイス型で実装クラスを扱う
  • 後のDB接続編で実装を差し替えるイメージをコメントで残す
  • 現時点では OracleEmployeeRepository は作成しなくてよい

課題が終わったら、できたところまでをGitに提出します。

まず、現在の状態を確認します。

Terminal window
git status

変更されたファイルを追加します。

Terminal window
git add .

コミットします。

Terminal window
git commit -m "Chapter14 インターフェイス"

ファイルサーバー上のリポジトリへpushします。

Terminal window
git push

Gitの操作でエラーが出た場合は、自己判断で同じ操作を繰り返さず、講師に確認してください。


提出前に、次の項目を確認してください。

  • interface を使ってインターフェイスを作成できている
  • インターフェイス名の先頭に I を付けている
  • クラスでインターフェイスを実装できている
  • インターフェイスで定義したメソッドをクラス側で実装している
  • インターフェイス型の変数を使えている
  • List<インターフェイス> を使えている
  • 複数のクラスを同じインターフェイスで扱えている
  • 複数のインターフェイスを実装できている
  • 抽象クラスとインターフェイスの違いをおおまかに説明できる
  • IEmployeeRepository の役割を説明できる
  • インデントが整っている
  • Gitにcommitしている
  • Gitにpushしている

この章では、インターフェイスについて学習しました。

この章で学んだ主な内容は次の通りです。

  • インターフェイスは、クラスが持つべき機能の約束を表す
  • インターフェイスは interface キーワードで定義する
  • C#では、インターフェイス名の先頭に I を付けることが多い
  • インターフェイスには、メソッドやプロパティを定義できる
  • 本研修では、インターフェイスには処理の中身を書かず、約束だけを書くものとして扱う
  • クラスは、インターフェイスを実装することで、その機能を持つことを示す
  • インターフェイスを実装したクラスは、約束されたメンバーを実装する必要がある
  • インターフェイス型の変数には、実装クラスのオブジェクトを代入できる
  • List<IPrintable> のように、異なるクラスを同じインターフェイスでまとめて扱える
  • 1つのクラスは、複数のインターフェイスを実装できる
  • 抽象クラスは共通の土台、インターフェイスは機能の約束として考えると分かりやすい
  • IEmployeeRepository のようなインターフェイスは、後のDB接続やWebアプリで実装を差し替える考え方につながる

次章では、例外処理 を学習します。

プログラムでは、入力ミス、ファイルが存在しない、DB接続に失敗するなど、さまざまなエラーが発生します。
例外処理を学ぶことで、エラーが発生したときにプログラムを安全に扱う方法を身に付けます。