【C#】抽象クラス・インターフェース

前提

C#の抽象クラス・インターフェースの話

抽象クラス

  • 定義
    インスタンスを生成出来ないクラスで、継承して利用することを前提としたクラス
    ※継承...クラスの共通部分を別クラス(A)にまとめ、Aを継承することでAのプロパティ・メソッドを継承先で宣言することなく利用できる仕組み

  • ポイント

    • クラスやメソッドの前にabstractキーワードを付ける
    • 抽象クラスの中の抽象メソッドでは処理を書かず定義だけ行い、処理は継承先の具象クラスで書く必要がある
    • 継承できる抽象クラスは1つのみ(抽象クラスに限らず、具象クラスを継承する際も継承可能なクラスのは1つ)
  • 実装例

public class Test{
    public static void Main(){
        
        var normal = new NormalUser();
        var str1 = normal.GetUserClassName();
        
        var admin = new AdminUser();
        var str2 = admin.GetUserClassName();
        
        System.Console.WriteLine(str1);
        System.Console.WriteLine(str2);
    }
}

abstract class AbstractUser {//抽象クラス
   abstract public string GetUserClassName(); //抽象メソッド
}

class NormalUser : AbstractUser {//抽象クラスを継承
    public override string GetUserClassName(){//抽象メソッドをオーバーライド
        return "NormalUser";
    }
}

class AdminUser : AbstractUser {//抽象クラスを継承
    public override string GetUserClassName(){//抽象メソッドをオーバーライド
        return "AdminUser";
    }
}
//出力結果
NormalUser
AdminUser

インターフェース

  • 定義
    メソッドの実装を強制し、機能を追加するための仕組み

  • ポイント

    • classではなく、interefaceキーワードを付ける※アクセス修飾子はpublic固定
    • インターフェースを実装したクラスは、インターフェースの処理を実装しなければいけない(抽象メソッドと同じ)
    • 複数のインターフェースの継承が可能
  • 実装例
public class Test{
    public static void Main(){
        
        var user = new User();
        var str1 = user.GetId();
        
        var product = new Product();
        var str2 = product.GetId();
        
        System.Console.WriteLine(str1);
        System.Console.WriteLine(str2);
    }   
}
interface IGetId{//インターフェース
    int  GetId();
}

class User : IGetId {
    public int GetId(){//インターフェースのメソッドを実装
        var userId = 1;//本来はUserテーブルにidを取得しに行くが、ここでは仮に定義
        return userId;
    }
}

class Product : IGetId {//インターフェースのメソッドを実装
    public int GetId(){//インターフェースのメソッドを実装
        var productId = 2;//本来はProductテーブルにidを取得しに行くが、ここでは仮に定義
        return productId;
    }
}
//出力結果
1
2

抽象クラスとインターフェースの使い分け

調べていくうちに想像より複雑だったため、また別の記事として作成予定。

参考

プロセス・スレッド・並列処理

プロセスとスレッド

プロセスやスレッドやマルチスレッドや並列処理など関係ありそうだけど、今まであやふやなまま放置していたので、まとめる。

プロセス

OSが実行しているプログラム。
WordやExcelなどタスクマネージャーで表示されるもの。 プロセスが並行処理されることを「マルチプロセス」と呼ぶ。

スレッド

プログラムの実行単位。
CPUのコアは1コアあたり、1スレッドしか実行できない。そのため、スレッド=CPUコアの処理単位。
ex)画面を描画するスレッド、キー入力を受け取るスレッドなど。

スレッドはプロセスの中に含まれ、1つのプロセスの中で複数のスレッドを動作させることができる。(マルチスレッド)

マルチスレッドにすることでCPUの複数のコアに処理を割り振れるため、シングルスレッドよりも処理を高速化できる。(CPUが複数コアに限る)

プロセスとスレッドの違い

  • 同じメモリ領域を共有するかしないか
    プロセスはOSからメモリ領域を割り当てられるため、各プロセスがメモリを共有することはない。
    ex)メモ帳に書いた文字がWordに反映されない。

    スレッドは同じメモリ領域を共有するため、マルチスレッドの場合はメモリの管理をしないとバグが発生する可能性がある。

並列処理(マルチスレッドプログラミング)

複数のスレッドを同時に実行するプログラムを作成することをマルチスレッドプログラミングと呼ぶ。

ただし実際は並行に処理を行っているのではなく、人間には分からない程高速でスレッドの切り替えをして、同時に処理を行っているようにみえている。

using System;
using System.Threading;
using System.Threading.Tasks;
 
public class TaskSample
{
   public static void Main()
   {
 
   // 並行処理
      var task1 = Task.Run(() => ThreadMethod("A"));
      var task2 = Task.Run(() => ThreadMethod("B"));
      task1.Wait();
      task2.Wait();
   }
 
   static void ThreadMethod(String str)
   {
      for(var i =0; i < 100; i++){
          Console.Write(str);
      };
      
   }
}
//値が交互に出力される
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  • スレッドセーフ
    複数のスレッドで同じリソースにアクセスしようとすると、想定の値にならないバグが発生する可能性がある。

    このバグを防止することをスレッドセーフと呼ぶ。 リソースを読み取り専用にする、排他制御(スレッドによる書き込み中は他のスレッドからのアクセスを不可にする)をかけるなど

参考

【Sass】@extendと@mixinの使い分け

定義したスタイルを複数のクラスで使用できるSassの@extendと@mixinの違いが分からなかったので、両者を比較して使い分けるべきケースをまとめる。

@extendの特徴

定義したスタイルを他のクラスに継承して使用できる

/* Sass */
.btn-base{
  border:1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
}
.btn-success{
  @extend .btn-base;
  background-color: green;
}
.btn-error{
  @extend .btn-base;
  background-color: red;
}
/* CSS */
.btn-base, .btn-error, .btn-success {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
}

.btn-success {
  background-color: green;
}

.btn-error {
  background-color: red;
}

プレースホルダーを使用する場合

継承元になったクラス(.btn-base)を利用しない場合は、プレースホルダー(%)を使用することでCSSコンパイルされない

/* Sass */
%btn-base{
  border:1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
}
.btn-success{
  @extend %btn-base;
  background-color: green;
}
.btn-error{
  @extend %btn-base;
  background-color: red;
}
/* CSS */
.btn-error, .btn-success {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
}

.btn-success {
  background-color: green;
}

.btn-error {
  background-color: red;
}

@mixinの特徴

定義したスタイルを他のクラスで呼び出して使用できる

/* Sass */
@mixin btn-base{
  border:1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
}
.btn-success{
  @include btn-base;
  background-color: green;
}
.btn-error{
  @include btn-base;
  background-color: red;
}
/* CSS */
.btn-success {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
  background-color: green;
}

.btn-error {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
  background-color: red;
}

引数を使用する場合

@includeに引数を渡すことで、呼び出し元のクラスごとにスタイルを調整することが出来る

/* Sass */
@mixin btn-base($bgc:transparent){
  border:1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
  background-color: $bgc;
}
.btn-success{
  @include btn-base(green);
}
.btn-error{
  @include btn-base(red);
}
/* CSS */
.btn-success {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
  background-color: green;
}

.btn-error {
  border: 1px solid;
  border-radius: 0.5rem;
  padding: 0.5rem;
  background-color: red;
}

比較

@extend

  • メリット

    • コード量が少ない
      継承元と継承先のクラスが1セレクタにグルーピングされるため、共通スタイルのコードの重複を防止できる
  • デメリット

    • 引数が使用できない
      @mixinと違い引数が使えない分、継承されるスタイルは固定になる

    • 可読性が下がる
      継承元と継承先のコードが離れるため、コードの可読性が落ちる。
      そのため、グルーピングできない関連性がないクラスへの@extendは控える。(関連性があるコードは距離が近く、関連性がないコードは距離が遠いため)

@mixin

  • メリット

    • 引数が使える
      @includeしたクラスごとにスタイルの調整が出来る

    • 可読性が高い
      コードが@includeしたクラスに全て記載されるため、可読性が高い

  • デメリット

    • コード量が増える
      @includeしたクラスに同じスタイルが記載されるため、コードが重複する。

まとめ

グルーピング出来るような関係性のあるスタイルは@extendを使用する
関係性がない、または引数を利用したいなら@mixinを使用する

まとめのまとめ

継承関係があるなら@extend、それ以外は@mixin

参考

【JavaScript】async/await

async/awaitとは

Promiseより快適に非同期処理を利用することが出来る構文。

async

  • 非同期関数を定義する
    関数名の前にasyncを書くと、その関数はPromiseオブジェクトを返す。
async function test() {
    return 'test';
}

test().then(value => {
    console.log(value); // => test
});

await

  • JavaScriptを待機させる
    async関数の中に記載すると、awaitを指定した関数のPromiseオブジェクトが結果を返すまでJavaScriptを待機させる。
function test(value) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    })
}

async function sample() {
    const result = await test(5);
    return result + 5;
}

sample().then(result => {
    console.log(result); // => 15
});

注意
async関数でない場合にawaitは使えないため、必ずセットで利用する

Promiseとの比較

先ほどのawaitの例で書いた処理をPromiseで書いた場合、async/awaitの方がより簡潔に非同期処理を書くことが出来る。

function test(value) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    })
}

function sample() {
    return test(5).then(result => {
        return result + 5;
    });
}

sample().then(result => {
    console.log(result); // => 15
});

参考

【JavaScript】Promiseオブジェクト

Promiseとは

JavaScriptの非同期処理のネストを深くせずに実装することができる仕組み。

背景

  • コールバック地獄
    JavaScriptの非同期処理はコールバック関数を利用して実装するが、処理が連続するとネストが深くなり、コードが肥大化してしまう問題があった。
// 引数を倍にする関数
function async(data, callback) {
    setTimeout(function() {
        callback(data * 2);
    }, 1000);
}

function callback_hell() {
    async(100, function(data) {
        console.log(data);// => 200
        async(data, function(data) {
            console.log(data);// => 400
            async(data, function(data) {
                console.log(data);// => 800
            });
        });
    });
}

そのため、連続する非同期処理をネストを深くせず同期処理のように記載するためにPromiseが利用される。

実装例

//Promiseオブジェクト
const async = value => {
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            if(value) {
                console.log(value)
                resolve('success')
            }else{
                console.log('値なし')
                reject('failure')
            }
        },1000)
    })
}
//thenメソッド
async('test1').then(
    response => {
        // => test1
        return async('test2')
        // => test2
    }
  ).then(
    response => { 
    },
    error => {
      console.log('エラー')
    }
)
  • Promiseオブジェクト
    非同期処理の最終的な完了もしくは失敗を表すオブジェクト
    Promiseオブジェクトのコンストラクターには3つの引数が必要。

    function(resolutionFunc, rejectionFunc){
    // typically, some asynchronous operation.
    }

    • resolutionFunc
      処理の成功を通知するための関数
    • rejectionFunc
      処理の失敗を通知するための関数
    • asynchronous operation
      処理本体

      上記コードでは処理としてseTimeOutを実行し、引数があればresolve,なければrejectを呼び出している。

  • thenメソッド
    Promiseが成功した場合と失敗した場合のコールバック関数を受け取るメソッド。

    p.then(onFulfilled[, onRejected]);
    p.then(value => {
    // fulfillment
    }, reason => {
    // rejection
    });

    • onFulfilled
      Promiseが成功した時に呼び出される関数(resolveによって呼び出し)
    • onRejected
      Promiseが失敗した時に呼び出される関数(rejectによって呼び出し)

メリット

  • 連続する非同期処理をネストせずに書ける
    Promiseを利用することで連続する非同期処理をthenメソッドでつなぐことができるため、コールバック地獄を回避でき、メソッドが肥大化することを防止できる。

  • エラー処理を必要な箇所にまとめることができる
    Promiseを利用することで、どの処理でエラーになってもthenメソッドで用意した失敗コールバック関数(reject)が呼び出されるため、メソッドごとにエラー処理を記載する必要がない。

参考

【Rails,Vue.js】JestでCSRFトークンを設定したaxiosを含むコンポーネントをテストするとき

事象

JestでCSRFトークンを設定したaxiosインスタンスを含むコンポーネントをマウントする際にTypeError: Cannot read property 'getAttribute' of nullになる

$ npm test
 ● Test suite failed to run

    TypeError: Cannot read property 'getAttribute' of null

       6 |         common: {
       7 |             'X-Requested-With': 'XMLHttpRequest',
    >  8 |             'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
         |                             ^
       9 |         }
      10 |     },
      11 | })

原因

マウントしたコンポーネントCSRFトークンが設定されているmetaタグが含まれていないため

Jestでマウントしたコンポーネントの中身をみると

wrapper = shallowMount(Message)
console.log(wrapper.html())
<div class="container">
    <div class="msg standard my-3"><span>メッセージ</span></div>
</div>

shallowMountしたコンポートにはmetaタグが含まれていない。
そのため、axiosが取得しようとしているmetaタグがないため、エラーになる。

対応

rails-ujsが発行したトークンを設定する

今回の原因がmetaタグからCSRFトークンを設定しているため、metaタグではなくCSRFトークンを発行してくれるモジュールであるrails-ujsを使う。

手順

インストール

npm install @rails/ujs

axiosインスタンスを生成しているファイルを編集する

import axios from 'axios'
import { csrfToken } from '@rails/ujs'; //追加

const http = axios.create({
    headers: {
        common: {
            'X-Requested-With': 'XMLHttpRequest',
            'X-CSRF-TOKEN': csrfToken() //追加
        }
    },
})


export default http

参考

【JavaScript】コールバック関数

コールバック関数

引数として渡される関数。
JavaScriptの関数はデータ型の1種のため、数値型や文字列型と同様に関数の引数・戻り値として扱うことができる。
「関数を引数、戻り値として扱う関数」を関数を高級関数と呼ぶ。

function execCallBack(callback){
    console.log('execCallBack')
    callback()
}

var callBack = function(){
    console.log('callBack')
}

execCallBack(callBack)

// 出力結果
// callBack

なぜコールバック関数が必要か

  • 非同期処理の順番を制御するため
    JavaScriptは前の処理結果を待たずに次の処理を実行する、非同期処理が可能。
    (例) サーバーからデータを取得している間にフロント側のhtmlを更新する
    ただし、前の処理結果を元にして次の処理に移りたい場合、コールバック関数によって処理の実行順序を制御することができる。
// 表示する値をセットする前に次の処理が実行されてしまう

function setMessage() {
  var msg;
  setTimeout(function() {
    msg = 'Hello World';
  })
  console.log(msg);
}

setMessage();  

// 出力結果
// undifined
// 表示する値がセットされた後に次の処理を実行する

function setMessage(callback) {
  var msg;
  setTimeout(function() {
    msg = 'Hello World';
    callback(msg)
  });
}

var showMessage = function (msg){
    console.log(msg)
}

setMessage(showMessage);  

// 出力結果
// Hello World

参考