プログラミングBlog

プログラミング学習用

ちょいちょい書いてます

C#でオブジェクト指向①

オブジェクト指向の抽象化

目的:朝のルーティンをオブジェクト指向の抽象化を使って実装していく。

まず、実際にコードを書いていく前にルーティーンを考えました。
起床、目覚まし止める、歯磨き、着替え、トイレ、朝ごはん.....etc 書きだしたらきりがないので抽象化してきます。

抽象可とは・・・思考における手法のひとつで、対象から注目すべき要素を重点的に抜き出して他は捨て去る方法である

抽象化 - Wikipedia wiki調べ。

というわけでまとめてみました。

平日の朝のルーティー

起床、準備、出勤

休日の朝のルーティー

起床、準備、まったり


イメージとしては基底クラスにこれらの3つのふるまいを抽象化して、
継承先に実装した処理を書いていく。
なので用意するものは基底クラス、休日クラス、平日クラス
基底クラスに起床、準備、出勤、まったり。 処理の開始メソッド。分岐メソッド。
このような感じでしょうか。
実際に書いていきます。

基底クラス

基底(Base)となるクラスを作成していきます。

  • abstractは継承先で必ず実装する。

  • virtualは継承先で実装するかしないかを選択できる。


出勤とまったりメソッドについては 平日だけど午前休だとか、休日だけどまったりできない日とかあるかもしれないので変更できるようvirtualにしてみました。

さきほどまとめた4つのメソッド 起床、準備、、出勤、まったり

        // 起床
        protected abstract void GetUp();

        // 準備
        protected abstract void Preparation();

        // 出勤
        protected virtual void Commuting()
        {
            Console.WriteLine("出勤します。");
        }

        // まったり
        protected virtual void Relax()
        {
            Console.WriteLine("まったりします。");
        }

これらの共通処理を実行するメソッド を書いていきます。
まずルーティング分岐とルーティンスタートメソッド2種類用意。
後々、ルーティンが増える??昼とか夜とか。。。かもしれないので分岐メソッドも定義してみました。
flgを立てて休日か平日によって処理が変わるようにしています。

分岐メソッド。 処理の開始メソッド。

        /// <summary>
        /// ルーティーン分岐
        /// </summary>
        public static void RoutinWork(bool isFolidayFlg)
        {
            if (isFolidayFlg)
            {
                new HolidayRoutin().Start(isFolidayFlg);
            }
            else
            {
                new WeekdaysRoutin().Start(isFolidayFlg);
            }
        }

        /// <summary>
        /// ルーティーンスタート
        /// </summary>
        public void Start(bool isFolidayFlg)
        {
            // 起床
            GetUp();

            // 準備
            Preparation();

            if (isFolidayFlg)
            {
                // まったり
                Relax();
            }
            else
            {
                // 出勤
                Commuting();
            }
        }

基底クラス

 /// <summary>
    /// ルーティーン基底クラス
    /// </summary>
    public abstract class RoutinWorkBase
    {

        /// <summary>
        /// ルーティーン分岐
        /// </summary>
        public static void RoutinWork(bool isFolidayFlg)
        {
            if (isFolidayFlg)
            {
                new HolidayRoutin().Start(isFolidayFlg);
            }
            else
            {
                new WeekdaysRoutin().Start(isFolidayFlg);
            }
        }

        /// <summary>
        /// ルーティーンスタート
        /// </summary>
        public void Start(bool isFolidayFlg)
        {
            // 起床
            GetUp();

            // 準備
            Preparation();

            if (isFolidayFlg)
            {
                // まったり
                Relax();
            }
            else
            {
                // 出勤
                Commuting();
            }
        }

        // 起床
        protected abstract void GetUp();

        // 準備
        protected abstract void Preparation();

        // 出勤
        protected virtual void Commuting()
        {
            Console.WriteLine("出勤します。");
        }

        // まったり
        protected virtual void Relax()
        {
            Console.WriteLine("まったりします。");
        }
    }

継承先のクラス

休日クラスと平日クラスにさきほど作成した基底クラスを継承してみましょう。
さきほど抽象化した起床、準備メソッドを実装していきます。
ここでオブジェクト指向ポリモーフィズムがでてきます。

ポリモーフィズムとは・・・プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。
アドホック多相(Ad hoc polymorphism):ある関数が、異なる型の引数に対してそれぞれ異なる実装を持つ場合。多くのプログラミング言語で関数の多重定義としてサポートされる。
パラメータ多相(Parametric polymorphism):コードが特定の型を指定せずに書かれることで、さまざまな型に対して透過的に使用できる場合。オブジェクト指向言語ではジェネリクスジェネリックプログラミングとしても知られる。関数型言語の分野ではパラメータ多相のことを指して単に多相性と呼ぶ場合がある。
部分型付け(Subtyping):部分型多相(subtype polymorphism)や包含多相(inclusion polymorphism)とも。共通の上位型をもつ複数の型を、1つの名前で扱う場合。オブジェクト指向言語の分野では部分型付けのことを指して単にポリモーフィズムと呼ぶ場合がある。

ポリモーフィズム - Wikipedia
Wiki調べ。

奥が深すぎてよくわかりませんが、オブジェクトのメソッドに多様なふるまいを持たせることなので、 overrideで処理の上書きをしていきます。

休日のルーティンクラス

    /// <summary>
    /// 休日のルーティン
    /// </summary>
    public class HolidayRoutin : RoutinWorkBase
    {
        protected override void GetUp()
        {
            Console.WriteLine("7:00に起きる。");
        }

        protected override void Preparation()
        {
            Console.WriteLine("7:10分から準備します。");
        }
    }

平日のルーティンクラス

    /// <summary>
    /// 平日のルーティン
    /// </summary>
    public class WeekdaysRoutin : RoutinWorkBase
    {
        protected override void GetUp()
        {
            Console.WriteLine("7:30に起きる。");
        }

        protected override void Preparation()
        {
            Console.WriteLine("7:40分から準備します。");
        }
    }

実行

     RoutinWorkBase.RoutinWork(true);
     RoutinWorkBase.RoutinWork(false);

結果

     7:00に起きる。
     7:10分から準備します。
     まったりします。
     7:30に起きる。
     7:40分から準備します。
     出勤します。

出勤を休日にする場合。

もし出勤が無くなって休日になった場合はCommuting(出勤)メソッドでをRelax()を呼ぶようにすればコードの修正がここだけで終わります。
virtualの場合は柔軟に対応できるので便利ですね。
ちょっと強引な気もするのでもっと良い方法ないか、デザインパターンの勉強もしていきたいと思います。

        protected override void Commuting()
        {
            base.Relax();
        }

結果

     7:00に起きる。
     7:10分から準備します。
     まったりします。
     7:30に起きる。
     まったりします。
     出勤します。

アプリ開発サークル勉強会⑨ 開催日時 2021年2月27日(土) 7:00-9:00

本日もこちらの問題やりました!

Q36-40 https://gist.github.com/kenmori/1961ce0140dc3307a0e641c8dde6701d

for文

for in

developer.mozilla.org

注: for...in はインデックスの順序が重要となる 配列 の繰り返しには使うべきではありません。

順序の保証がないそうです。
index番号を列挙したkey値が借り変数keyに入る。

var numbers = [1, 2, 3, 4, 5];

for (key in numbers) {
    console.log(key);
}

結果: 0,1,2,3,4

hogeが表示される例

var data = ['apple', 'orange', 'banana'];

Array.prototype.hoge = function () { }

for (var key in data) {
    console.log(key);
}

結果:

0,1,2,hoge

for of

順序の保証の保証がされる反復処理をしたい場合は for ofを使う。
dataに列挙されたvalueが仮変数に入る。
hogeが表示されない。

var data = ['apple', 'orange', 'banana'];

Array.prototype.hoge = function () { }

for (var value of data) {
    console.log(value);
}

結果:

apple,orange,banana

AWS ELB ALB作成

ELBを作成してnginxの負荷分散を確認したい。

ELBとは

アプリケーションのトラフィックを複数のターゲット分けることで負荷分散を可能にする。
4種類のElastic Load Balancerが存在し、耐障害性を高めるのに必要な高い可用性、自動スケーリング、堅牢なセキュリティが特徴。

Elastic Load Balancing(複数のターゲットにわたる着信トラフィックの分配)| AWS

アプリケーションが落ちた際に、別のインスタンスに紐づけしておけば、
完全にサービスが止まることはないので
故障に備えた設計(Design for Failure)を行うことができますね。


ELBを作っていきます。
VPC Subnet RouteTable InternetGateWay SecurityGroup EC2Instance
このへんはあらかじめ作っておきましょう。

ELB

マネージメントコンソールからEC2に入ります。
その後、ロードバランサーの作成。
f:id:Tokuty:20210223231237p:plain
種類は3 + 1ありますが、
ELBの動きをnginxを使ってhttp通信で確認したいのでApplication Load Balancerを選択。
f:id:Tokuty:20210223143931p:plain

ロードバランサーの設定

リスナーはデフォルトでhttpのポート80が設定されているのでそのまま。
アベイラビリティーゾーンにVPCと負荷分散させたいEC2を設置してあるSubnetを設定します。
注意点はアベイラビリティーゾーンが同じではないのとIGWが設定してあること。
f:id:Tokuty:20210223144103p:plain

セキュリティーグループ

EC2にログインする時のsshとhttpがインバウンドルールに設定してあるセキュリティーグループを選択。

ルーティンググループ

ここでルーティングを設定していきます。 ヘルスチェックのパスに負荷分散したいルートを設定します。
特に要件がないのですべてデフォルトで設定。
f:id:Tokuty:20210223152502p:plain 負荷分散させたいEC2インスタンスを登録。
f:id:Tokuty:20210223145312p:plain
説明の状態がProvisioningからactiveになれば準備完了。
EC2インスタンスアプリケーションサーバーが起動状態で、DNSからアクセスすると負荷分散の確認ができます。
次はnginxの設定をしていきます。

Nginx設定

EC2にssh接続にてログインした後に、Extras Libraryからnginxをinstallしていきます。
aws.amazon.com

amazon-linux-extras installできるpackageの確認
amazon-linux-extras install nginx1 install
デフォルト設定だと/usr/share/nginx/html/直下のindex.htmlが
最初に表示されるページとなります。
index.htmlの中身をELBにて切り替わるのを確認したいので適当に変更しておきます。 /usr/share/nginx/html/index.html 場所
systemctl start nginxnginxを起動

ELBのDNS名をURLに入力して確認します。
f:id:Tokuty:20210223150148p:plain
更新ボタンを押すことで切り替わることが確認できました。
f:id:Tokuty:20210223150158p:plain
試しにインスタンスを一つ起動停止にしてみると、このような結果となります。
ステータスがhealthyからunusedに変化したことが確認できます。
正常?がいいえとなります。
この状態でELBのDNS名にアクセスすると起動しているEC2インスタンス
index.htmlが表示されることが確認できました。
f:id:Tokuty:20210223152650p:plain
監視もできるので原因調査もできますね。

エラー

もしこのようなエラーが出た場合は、ターゲットにEC2インスタンスが設定してあるかを調べましょう。
f:id:Tokuty:20210223143519p:plain
もし何も表示されない場合はセキュリティーグループを見直してみましょう。
httpとポート80が設定されてないことが多いです。

nginxについて

gakumon.tech

アプリ開発サークル勉強会⑧ 開催日時 2021年2月20日(土) 7:00-9:00

Javascript アロー関数について①

アロー関数と通常関数の違いについて調べていました。
調べる前は通常関数の書き方を簡易的にしただけのイメージが強かったのですが、
どうやら違うようで使えなくなる機能があったため、使いどころに注意が必要です。

arguments

コードを書いて比較していきます。 引数の合計値を求める関数を定義しました。

通常関数

function sum() {
    var total = 0;
    for (var i = 0; i < arguments.length; i++) {
        total += arguments[i];
    }
    return console.log(total);
}

sum(1, 2);

結果:

3

アロー関数

var sum = () => {
    var total = 0;
    for (var i = 0; i < arguments.length; i++) {
        total += arguments[i];
    }
    return console.log(total);
}

sum(1, 2);

[object Object]こちらに値を代入しようとしていますが、argumentsが定義されていないので
エラーとなりました。
結果:

0[object Object]function require(path) {
      return mod.require(path);

スコープについて

スコープとは、直訳すると範囲という意味で、プログラミングだと 定義した変数がどの範囲まで使うことができるかを指します。 調べた限り、4つのスコープが存在するようです。
グローバルスコープ、ローカルスコープこのへんはどの言語でも共通の認識かと思われます。
グローバルは全体、ローカルは関数の中で変数を宣言した場合その範囲でしか使えない。
レキシカルスコープとダイナミックスコープについて。
変数のスコープの決まり方ですが、レキシカルスコープは宣言した時点で決定する。
ダイナミックスコープは実行時に決定する。
アロー関数はレキシカルスコープのようです。

this

thisの取り扱いについて。
難しいのでコードを書いて検証してみました。

引数の値の合計値を返す関数

通常関数

定義した関数の一つ上の階層にあるオブジェクトを返す。

function sum1(a, b) {
    console.log(this);
    return a + b;
}

sum1(1, 2);

結果:

{Object [global] {
  global: [Circular],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Function]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Function]
  }
}

アロー関数

thisは定義されていないため、空っぽを返す。

var sum2 = (a, b) => {
    console.log(this);
    return a + b
}

sum2(1, 2);

結果: {}

testにvalueとtest関数を定義

通常関数

定義した関数の一つ上の階層にあるオブジェクトを返す。
この場合だと変数test1です。

var test1 = {
    value: 1,
    test: function () {
        console.log(this);
    }
}

test1.test();

結果:

{ value: 1, test: [Function: test] }

アロー関数

thisは定義されていないため、空っぽを返す。

var test2 = {
    value: 1,
    test: () => {
        console.log(this);
    }
}

test2.test();

結果:

{}

thisの動きが全く違いますね。。。
他にもたくさん違いがあるので、覚えることが多そうです。

参考サイト

qiita.com wemo.tech

AWS CloudFormationメモ①

CloudFormationメモ①

RDS

公式のリファレンスから引用。
AWS::RDS::DBSubnetGroup - AWS CloudFormation

AWSTemplateFormatVersion: "2010-09-09"
Resources: 
  myDBSubnetGroup: 
    Properties: 
      DBSubnetGroupDescription: description
      SubnetIds: 
        - subnet-7b5b4112
        - subnet-7b5b4115
      Tags: 
        - 
          Key: String
          Value: String
    Type: "AWS::RDS::DBSubnetGroup"

SubnetIds:
RDSにアタッチするSubentは異なるリージョン間のSubnetでないとエラーとなるため注意。

AvailabilityZone

AvailabilityZoneを設定する項目にap-north-east1(東京)このようなハードコーディングしていましたが、
マネージメントコンソール右上のAZと連動しているため、右上のAvailabilityZoneを東京以外に選択をしていた場合はAZが見つからないためエラーとなります。
なのでパラメーターとして選べるように。

Parameters:
 AvailabilityZonePublicSubnet:
 Type: AWS::EC2::AvailabilityZone::Name

Resources:
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId:
        Ref: VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: !Ref AvailabilityZonePublicSubnet
      Tags:
        - Key: Name
          Value: PublicSubnet

NetworkACL

  PublicNetworkACLInboundRule01:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId:
        Ref: PublicNetworkACL
      Egress: false
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      CidrBlock: 0.0.0.0/0

  PublicNetworkACLOutboundRule:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId:
        Ref: PublicNetworkACL
      Egress: true
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      CidrBlock: 0.0.0.0/0

Egressfalse:インバウンド true:アウトバウンド
Protcol TCP:6 すべて:-1
全許可のルールを追加するために-1を設定。
NetworkACLはデフォルトで全拒否のルールがインバウンドとアウトバウンドに設定されています。

EndPoint

yum updateができなかったときに作成したエンドポイント。
Amazon Linux2のRepositoryにアクセスできるようポリシーを設定しています。

  # Create Endpoint
  S3Endpoint:
    Type: "AWS::EC2::VPCEndpoint"
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Sid: "AmazonLinux2AMIRepositoryAccess"
            Principal: "*"
            Action:
              - "s3:GetObject"
            Resource:
              - "arn:aws:s3:::amazonlinux.*.amazonaws.com/*"
      RouteTableIds:
        - !Ref PublicRouteTable
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
      VpcId: !Ref VPC

EC2

新規作成の場合、AMIが存在しないため、パラメーターで新しいAMIを発行するように。
KeyPairの設定。password、アクセスキー、などは必ずパラメーターとして設定できるようにする。

Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
    Type: "AWS::EC2::KeyPair::KeyName"
  AMIID:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
  
Resources:
  PublicEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      Tags:
        - Key: Name
          Value: PublicEC2Instance
      ImageId: !Ref AMIID
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          GroupSet:
            - !Ref PublicSecurityGroup
          SubnetId:
            Ref: PublicSubnet

- AssociatePublicIpAddress: "true" publicIPAddressを設定しています。
これを設定しないと接続できなくなります。

アプリ開発サークル勉強会⑦ 開催日時 2021年2月13日(土) 7:00-9:00

本日もこちらの問題やりました!

Q31-35 https://gist.github.com/kenmori/1961ce0140dc3307a0e641c8dde6701d

Object.getOwnPropertyDescriptor

オブジェクトのプロパティの属性を返す。 属性については前回の勉強会でも取り上げましたが、復習もかねてもう一度。
JavaScriptにおけるオブジェクトのプロパティとは、オブジェクト指向におけるプロパティ(フィールド)と同じ意味だと考えられます。
つまり、プロパティとはなんらかの情報のことですね。 属性とは読み取り専用、書き込み専用など、のことをさします。
まずはtsuyahimeというオブジェクトを定義します。

let tsuyahime = {
    name: 'つや姫',
    color: 'white',
    origin: '山形'
}

次にプロパティに定義されている属性を、getOwnPropertyDescriptorで表示させます。

console.log(Object.getOwnPropertyDescriptor(tsuyahime, 'origin'));

結果:

{ value: '山形', writable: true, enumerable: true, configurable: true }

デフォルトだと各属性の値はtrueのようです。
次はこれらの属性値を変更してみましょう。

defineProperty

属性値の定義、変更
まず各属性について、設定できる項目。
value:値
writable:書き込み
enumerable:列挙
configurable:削除

Object.defineProperty(tsuyahime, 'water', {
    value: 20,
    writable: false,
    enumerable: false,
    configurable: false
});

// 書き込み
tsuyahime.water = 30;
// 列挙
console.log(Object.keys(tsuyahime));
// 削除
delete tsuyahime.water;

console.log(tsuyahime.water);

結果:

[ 'name', 'color', 'origin' ]
20

値が変更されず、非列挙となり、削除できなくなりました。
可能にしたい場合はtrueに変更する

オブジェクトの参考サイト

オブジェクトでの作業 - JavaScript | MDN

map

配列の全ての要素を呼び出し、その結果の値を含む新しい配列を作成する。
今までは空の配列を作成し、配列の詰替えを行っていましたが、そんなことせずともできるように。

const nums = [1, 2, 3, 4, 5];

var newNums = nums.map(function (num) {
    return num;
})

console.log(newNums);

結果:

[ 1, 2, 3, 4, 5 ]

引数追加することでindex番号と配列が取得できます。
このへんはforeachと一緒ですね。
他の言語でもindex番号が取れるので、覚えておきましょう。

var newNums = nums.map(function (num, index, arr) {
    console.log(index);
    console.log(arr);
    return num;
});

結果:

[ 1, 2, 3, 4, 5 ]   
1
[ 1, 2, 3, 4, 5 ]
2
[ 1, 2, 3, 4, 5 ]
3
[ 1, 2, 3, 4, 5 ]
4
[ 1, 2, 3, 4, 5 ]

argments

関数に渡された引数の値を含み、関数内からアクセスできる。
ちょっとした計算するときに使えそう。

function sum() {
    var total = 0;
    for (var i = 0; i < arguments.length; i++) {
        total += arguments[i];
    }
    return console.log(total);
}

sum(1, 2);

結果:
3

ショートカットキー

vscodeのショートカットキーの話も出てきましたが。
表示→パレッド→基本設定:キーボードショートカットキーを開く
使えそうなショートカットキーはここで探すと良い。
CTRL + K CTRL + C コメントの追加 CTRL + C CTRL + U コメントの解除

OracleDB 大量のデータ作成

OracleDB 大量のデータ作成

テーブル作成

CREATE TABLE test(
    id number(10),
    name varchar(10),
    code varchar(5),
    mail varchar(255)
)

ランダムな数値作成

1-9999までの数値 + 浮動小数点を返す。 DBMS_RANDOM.VALUE(1,9999)
結果:1366.243219707729031003322765651467096256
小数点は必要ないのでTRUNCで切ります。
TRUNC(DBMS_RANDOM.VALUE (1, 9999), 0)
ランダムな数値の生成完成。

ランダムな文字列を作成

今回は大文字のアルファベット生成と数字を生成。
第一引数はルールごとに記述が違うのでその都度変更していく。
DBMS_RANDOM.STRING('x', 8) || '@co.jp'
結果:336L0ZGR@co.jp
ランダムな文字列の完成。

参考サイト

oracle.se-free.com

データをINSERT

一件のデータを挿入。

INSERT 
INTO test 
VALUES ( 
    TRUNC(DBMS_RANDOM.VALUE (1, 9999), 0)
    , 'test'
    , DBMS_RANDOM.STRING('x', 5)
    , DBMS_RANDOM.STRING('x', 8) || '@co.jp'
); 

ランダムなデータ。

結果:   ID:8183        NAME:test     CODE:HSABS       MAIL:48PQFKAV@co.jp

100件のデータをINSERT

BEGIN FOR i IN 1..100 LOOP 
INSERT 
INTO test 
VALUES ( 
    TRUNC(DBMS_RANDOM.VALUE (1, 9999), 0)
    , 'test'
    , DBMS_RANDOM.STRING('x', 5)
    , DBMS_RANDOM.STRING('x', 8) || '@co.jp'
); 

END LOOP; 

END;

エラー発生。
f:id:Tokuty:20210211114154p:plain
このエラーに1時間ほど悩まされました。
まず考えたのが 3つほど。

  1. シンプルに記述ミス。
  2. BEGIN ENDFOR LOOP END LOOP等、閉じる位置が対応していない可能性。
  3. プロシージャ権限関係。

結果的にどれも違いました 笑
でも勉強になったので良かったかな。
解決方法としてはSQLの実行オプションでギャレットの位置を";"→"/"に変更すれば読み込んでくれるようです。(参考サイト


再実行結果
f:id:Tokuty:20210211115045p:plain

解決方法の参考サイト

A5:SQL Mk-2でストアドプロシージャがエラーになるときの解決方法 | 25歳でフリーランス28歳で起業したエンジニア -じゃけぇ- のあれこれ
助かりました!ありがとうございます。

ショートカットキー

A5の機能についてもっと知っていればエラー解決できたはず。
ツールには慣れていきたいので、今回使った役に立つショートカットキーを残しておきます。
* CTRL + K コメントアウト
* CTRL + SHIFT + K コメントアウト解除
* CTRL + Q SQLの整形
SQLの整形は記述はあってるけど読み込んでくれない時などによく使います。