Flutter初心者の学習記録 第7回:オブジェクト指向の基本原則を理解する

オブジェクト指向プログラミングの三大柱:継承、多態性、カプセル化
こんにちは、ジミーです!今回のブログでは、オブジェクト指向プログラミング(OOP)の基本的な概念である継承、多態性、そしてカプセル化について解説します。これらの概念はDartを含む多くのプログラミング言語の基盤となっており、Flutterアプリ開発においても非常に重要です。
継承(Inheritance)
継承は既存のクラス(親クラスまたはスーパークラス)から特性を受け継いで新しいクラス(子クラスまたはサブクラス)を作成する機能です。これにより、コードの再利用性が高まり、階層構造を作ることができます。
Dartでの継承の例を見てみましょう:
// 親クラス
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('動物が鳴きます');
}
void eat() {
print('$nameは食べています');
}
}
// 子クラス
class Dog extends Animal {
Dog(String name) : super(name);
@override
void makeSound() {
print('$nameはワンワン!');
}
void fetch() {
print('$nameは物を取ってきます');
}
}
void main() {
var dog = Dog('ポチ');
dog.eat(); // 親クラスから継承したメソッド
dog.makeSound(); // オーバーライドしたメソッド
dog.fetch(); // 子クラス固有のメソッド
}
Flutterでは、StatelessWidget
やStatefulWidget
を継承してカスタムウィジェットを作成することがよくあります:
class CustomButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
const CustomButton({required this.text, required this.onPressed});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(text),
);
}
}
多態性(Polymorphism)
多態性は「多くの形態を持つ」という意味で、同じインターフェースが異なるクラスで異なる動作をすることを可能にします。簡単に言えば、同じメソッド名が異なる動作をする機能です。
多態性の例:
abstract class Shape {
double calculateArea();
}
class Circle extends Shape {
double radius;
Circle(this.radius);
@override
double calculateArea() {
return 3.14 * radius * radius;
}
}
class Rectangle extends Shape {
double width;
double height;
Rectangle(this.width, this.height);
@override
double calculateArea() {
return width * height;
}
}
void printArea(Shape shape) {
print('面積は${shape.calculateArea()}です');
}
void main() {
var circle = Circle(5);
var rectangle = Rectangle(4, 6);
printArea(circle); // 出力: 面積は78.5です
printArea(rectangle); // 出力: 面積は24です
}
Flutterでの多態性の応用例:
abstract class DataProvider {
Future<List<String>> fetchData();
}
class NetworkDataProvider extends DataProvider {
@override
Future<List<String>> fetchData() async {
// ネットワークからデータを取得するロジック
return ['ネットワークデータ1', 'ネットワークデータ2'];
}
}
class LocalDataProvider extends DataProvider {
@override
Future<List<String>> fetchData() async {
// ローカルストレージからデータを取得するロジック
return ['ローカルデータ1', 'ローカルデータ2'];
}
}
class DataScreen extends StatelessWidget {
final DataProvider dataProvider;
DataScreen({required this.dataProvider});
@override
Widget build(BuildContext context) {
return FutureBuilder<List<String>>(
future: dataProvider.fetchData(),
builder: (context, snapshot) {
// データ表示のUI構築ロジック
// ...
},
);
}
}
カプセル化(Encapsulation)
カプセル化はクラスのデータ(属性)と、そのデータを操作するメソッドをひとまとめにする概念です。また、クラスの内部データへのアクセスを制限し、データの整合性を保護します。
Dartでのカプセル化の例:
class BankAccount {
// プライベート変数(アンダースコアで始まる)
double _balance = 0;
// コンストラクタ
BankAccount([double initialBalance = 0]) {
if (initialBalance >= 0) {
_balance = initialBalance;
}
}
// ゲッターメソッド
double get balance => _balance;
// 入金メソッド
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
print('入金完了:現在の残高は $_balance 円です');
} else {
print('不正な入金額です');
}
}
// 出金メソッド
bool withdraw(double amount) {
if (amount > 0 && _balance >= amount) {
_balance -= amount;
print('出金完了:現在の残高は $_balance 円です');
return true;
} else {
print('出金できません');
return false;
}
}
}
void main() {
var account = BankAccount(1000);
print('初期残高: ${account.balance}');
account.deposit(500);
account.withdraw(200);
// 直接_balanceにアクセスすることはできない
// account._balance = -1000; // エラー
}
Flutterでのカプセル化の応用例:
class UserModel {
String _name;
String _email;
int _age;
UserModel(this._name, this._email, this._age);
// ゲッター
String get name => _name;
String get email => _email;
int get age => _age;
// セッター(バリデーション付き)
set name(String value) {
if (value.isNotEmpty) {
_name = value;
}
}
set email(String value) {
if (value.contains('@')) {
_email = value;
}
}
set age(int value) {
if (value >= 0) {
_age = value;
}
}
// データを整形して返すメソッド
Map<String, dynamic> toJson() {
return {
'name': _name,
'email': _email,
'age': _age,
};
}
// JSONからインスタンスを作成するファクトリメソッド
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
json['name'] as String,
json['email'] as String,
json['age'] as int,
);
}
}
まとめ
オブジェクト指向プログラミングの三大原則である継承、多態性、カプセル化は、Flutterアプリケーション開発において非常に重要な概念です。これらを理解し適切に活用することで、保守性が高く、拡張しやすい、堅牢なアプリケーションを開発することができます。
- 継承は親クラスの特性を子クラスに引き継ぎ、コードの再利用性を高めます
- 多態性は同じインターフェースで異なる動作を実現し、柔軟なコードを可能にします
- カプセル化はデータとその操作をひとまとめにし、データの整合性を保護します
次回のブログでは、これらの概念をさらに発展させ、実際のFlutterアプリケーション開発でどのように活用するかについて詳しく解説します。ご質問やコメントがありましたら、ぜひ下のコメント欄にお寄せください!
良いFlutter開発ライフを!