1.はじめに
色々あったというか転職先で必要になったため、C#の勉強を開始した。
時々見かける、メソッドのみが羅列されている謎のクラス、インターフェース。
今回の目的は、インターフェースとは何かを体感することにしている。
2.インターフェースって何?
インターフェースについてC#入門の本で調べてみた。
- 親クラスからのメソッドは宣言のみで、フィールドを生成することはできない。
- 抽象クラスと同じように、インスタンスを生成できない
- 抽象クラスの概念をさらに推し進めたもの
- 呼び出すときは、親クラスをインターフェースでキャストして使うことができる
箇条書きの3つ目が気になる。
抽象クラスを誇張したもの?ザコシショウか?⇒結論、そういう意味ではなかった。
下記のような感じで作るらしい。
interface インターフェース名
{
親クラスのメソッド1(引数)
親クラスのメソッド2(引数)
}
わかんない。イマイチわからないのだ。
例を見てもよくわからない。
何で、わざわざ親クラスの一部のメソッドだけ宣言しているのか。
親クラスの一部の機能だけしか、使わない場合ってあるのか?
色々かんがえたところ、
日頃からお世話になっている (当たらないので課金を続けている) Lotoの購入で使えそうかも
と気が付いた。
3.ロトの購入について
3-1.ロトの購入処理手順
ここでロトを購入するときの処理内容を考える。
1.購入するとき、ロト6やロト7という銘柄を決める。
2.購入の仕方も「自分で番号を決めて購入」か「クイックピック」がある。
(厳密にいえば、半分ランダム、半分自己選択という混合型もあるが(クラス名:キューピーハーフ)、
今回は、全番号自己選択 or クイックピックで考える)
※キューピーハーフクラスは、某会社の商品名ともかぶるし今回は作成しない。
全番号クイックピックを指定した時、自分で番号を選択することができない。
番号選択の時は、全番号クイックピックを使うことができない。
(a)クイックピック
ロト6の場合は、1~43までの数字6つがランダムに選ばれる方式
ロト7の場合は1~37までの数字7つがランダムに選ばれる方式。
(b)自分で数字選択
自分で数字を決めて入力する方式。
数字の入力回数は、ロト6では購入本数6、ロト7では購入本数7とする。
3.購入本数分の金額を払う。
(ロト6は一本200円、ロト7は一本300円)
3-2.ロト関連クラスについて
(1)ロトクラス
ロトクラス:自己番号選択インターフェース,クイックピックインターフェース
{
銘柄(ロト6かロト7か)
表示名
購入方法(クリックピックか自己選択か)
最大数値
購入本数
価格
自己選択関連メソッド
クイックピック関連メソッド
購入金額計算メソッド
}
(2)自己番号選択インターフェース
自己番号選択インターフェース
{
自己選択関連メソッド
購入金額計算メソッド
}
(3)クイックピックインターフェース
クイックピックインターフェース
{
クイックピック関連メソッド
購入金額計算メソッド
}
実行環境:Windows 10 home
visual studio 2022
4.実行画面
4-1.ロト6をクイックピックで購入
4-2.ロト7を数字を選択して購入
5.ソース
5-1.購入の選択
(1)loto6かloto7か
loto6を購入する場合は0を、loto7を購入したい場合は1を入力
(2)購入方式
クイックピック:0
自己選択:1
自己選択式の場合、以下の制限が必要になる。
1)ロト6では1~43までの数字
ロト7では1~37までの数字までしか購入できない。
2)1組の購入数字内に、同じ数字は選択できない。
(3)購入本数
自己選択なら、3本まで購入可能
using ConsoleApp_loto;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp_loto
{
class Program0
{
//入力文字列のチェック
public static Boolean Check_input(string s0, int nmax = 0)
{
int type0;
//入力文字列が数字以外の時
if (int.TryParse(s0, out type0) == false)
{
return true;
}
type0 = int.Parse(s0);
//自己選択型での入力数字
if (nmax > 2)
{
return (type0<1 || type0>nmax) ? true : false;
}
//自己選択型の購入本数
if (nmax == 2)
{
return (type0>3 || type0<0) ? true : false;
}
//購入タイプ選択
if (nmax==0)
{
return (type0>1 || type0<0) ? true : false;
}
//購入タイプQPの整数での本数入力
return false;
}
public static void Main(string[] args)
{
int i, j;
int rettype = 0;
string retname = "";
int nmax = 0;
string s, s1, s2, s3;
int type0 = 0;
int type2 = 0;
int n = 0;
int price0 = 0;
string tmpstr0 = "";
Console.WriteLine("クイックピックの場合は0を、自分で選択する場合は1を入力してください。");
s1 = Console.ReadLine();
Console.WriteLine("ロト6は0,ロト7は1を入力してください");
s2 = Console.ReadLine();
if (Check_input(s1) == true || Check_input(s2) == true)
{
Console.WriteLine("不正な値です");
return;
}
Console.WriteLine("購入本数(自分で選択の場合は3本まで)");
s3 = Console.ReadLine();
type0 = int.Parse(s1);
type2 = int.Parse(s2);
//ロトの銘柄
rettype = (type2 == 0) ? 6 : 7;
//一本当たりの金額
price0 = (type2 == 0) ? 200 : 300;
//くじ番号の最大値
nmax = (type2 == 0) ? 43 : 37;
//クイックピック
if (type0 == 0)
{
if (Check_input(s3,1) == true)
{
Console.WriteLine("不正な値です");
return;
}
n = int.Parse(s3);
retname=(type2==0)? "ロト6(QP)": "ロト7(QP)";
Loto kuji = new Loto();
kuji.Name = retname;
kuji.Type1 = rettype;
kuji.Num1 = n;
kuji.Price = price0;
kuji.Loto_max = nmax;
Iquick_pick ltqp = (Iquick_pick)kuji;
ltqp.Buyqp();
ltqp.PrintTotalAmount();
}
//自分で選択した場合
if (type0 == 1)
{
if (Check_input(s3, 2) == true)
{
Console.WriteLine("不正な値です");
return;
}
n = int.Parse(s3);
string[] tmpstr1 = new string[n];
int n2;
retname = (type2 == 0) ? "ロト6(自己選択)" : "ロト7(自己選択)";
//n本分の数字を入力
for (i = 0; i < n; i++)
{
List<int> retint_list = new List<int>();
for (j = 0; j < rettype; j++)
{
Console.Write((i + 1) + "回目:" + (j + 1) + "番目(1~" + nmax + ")までを指定 ");
s = Console.ReadLine();
if (Check_input(s, nmax) == true)
{
Console.WriteLine("不正な値です");
return;
}
n2 = int.Parse(s);
if (retint_list.Contains(n2) == true)
{
Console.WriteLine("同じ値が入力されています");
return;
}
retint_list.Add(n2);
}
Console.WriteLine();
tmpstr1[i] = string.Join(",", retint_list);
retint_list.Clear();
}
tmpstr0 = string.Join(" ", tmpstr1);
Loto kuji = new Loto();
kuji.Name = retname;
kuji.Type1 = rettype;
kuji.Num1 = n;
kuji.Mynumbers = tmpstr0;
kuji.Price = price0;
kuji.Loto_max = nmax;
Inumber_select mylt = (Inumber_select)kuji;
mylt.Buymynum();
mylt.PrintTotalAmount();
}
}
}
}
ロトクラス
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp_loto
{
internal class Loto : Inumber_select, Iquick_pick
{
private string _name;
private int _num1;
private int _type1;
private string _mynumbers;
private int _loto_max;
private int _price;
public string Name
{
set { _name = value; }
get { return _name; }
}
//ロト6やロト7など銘柄を表す数字
public int Type1
{
set { _type1 = value; }
get { return _type1; }
}
//購入本数
public int Num1
{
set { _num1 = value; }
get { return _num1; }
}
//自分で選択した数字を連結した文字列
public string Mynumbers
{
set { _mynumbers = value; }
get { return _mynumbers; }
}
//選択する最大値
public int Loto_max
{
set { _loto_max = value; }
get { return _loto_max; }
}
//一本当たりの価格
public int Price
{
set { _price = value; }
get { return _price; }
}
//クイックピックで購入
public void Buyqp()
{
Random rand = new Random();
int nn;
//可変配列
List<string> ret_list = new List<string>();
for (int i = 0; i < _num1; i++)
{
List<int> lotoqp_list = new List<int>();
for (int j = 1; j <= _loto_max; j++)
{
lotoqp_list.Add(j);
}
int[] tmparr = new int[_type1];
for (int j = 0; j < _type1; j++)
{
nn = rand.Next(_loto_max - j);
tmparr[j] = lotoqp_list[nn];
lotoqp_list.RemoveAt(nn);
}
ret_list.Add(string.Join(",", tmparr));
lotoqp_list.Clear();
}
for (int i = 0; i < _num1; i++)
Console.WriteLine(_name + ": " + (i + 1) + "回目:" + ret_list[i]);
}
//合計金額表示
public void PrintTotalAmount()
{
int total = 0;
total = _price * _num1;
Console.WriteLine("購入金額は" + total + "です");
}
public void Buymynum()
{
string[] tmpstr3 = new string[_num1];
tmpstr3 = _mynumbers.Split(" ");
int i, j;
for (i = 0; i < _num1; i++)
Console.WriteLine(_name + ":" + (i + 1) + "回目:" + tmpstr3[i]);
}
}
}
自己選択式
- 購入数分の選択した数字を表示
- 購入金額を表示
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp_loto
{
internal interface Inumber_select
{
void Buymynum();
void PrintTotalAmount();
}
}
クイックピッククラス
- クイックピック方式の数字を表示
- 購入金額を表示
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp_loto
{
internal interface Iquick_pick
{
void Buyqp();
void PrintTotalAmount();
}
}
6.気になったこと
インターフェースについては体感できた。
それよりも地味に大変なことがあった。
入力文字列のチェックだ。
if,elseという判定文だ。
簡単なif文で4行書くことになる ⇒これ!!!
{カッコだけで1行使うのだ。
しかも、対になるカッコも必要なのだ。)
行数削減のため、3項演算子を駆使したのだ。
7.インターフェースのメリット
改めてインターフェースについて考えてみた。
2つの共通点が多いが一部の処理が違うクラスを作りたいとする。
そんな時いちいちコピペして、クラスを作るのは効率が悪い。
さらに何かあったときに、 [例えば2つのクラスに共通する処理を変更するときは親クラスだけ変更]
できた方が良い。
全体のコード量も削減できる。
メソッドのみが羅列されている謎のクラスのメリットだったのだ。