JavaScriptにおける立体設計原理(第3部)—界面偏析原理と依存性反転
良いデザインは明白です.大きなデザインは透明です.
歓迎の人々は、あなたが今までこのシリーズを楽しんでいた願っています.これはシリーズの最終的な部分です.前の記事では、2番目と3番目の立体設計原理(オープンクローズ原理とliskov置換原理)を見ました.界面偏析原理と依存性反転である最後の2つの原理に焦点を当てた.
この記事のパート1またはパート2を読んでいない場合は、ここにアクセスできます. 第1部 第2部 また、私のgithubの上の完全なコード例にアクセスすることもできます
https://github.com/Caleb-Mantey/solid-design-principles-in-js
今すぐ私たちのコードがどのように見えるかを要約することができます
SMTPサービスの動作を設定する基本クラス( MailErsmtService ) MailErsmtPServiceクラスから継承し、SMTPサービスに接続する子クラス( postMarksmtService ) mailerSMTPサービスクラスから継承し、SMTPサービス( SendDridDSMTPサービス)に接続する子クラス テキストをテキスト形式でフォーマットするクラス( TextFormatter ) HTMLでメールをフォーマットするクラス メールを送るクラス このコードは、それがインスタンス化され、このようなメールを送信するために使用することができます私たちのメーラークラスで一緒に結ばれます.
この原理は
この原理は
この機能を使用すると、我々はインターフェイスを追加しました
では、より良いアプローチを見てみましょう.
この原理は2つの部分に分けられ
上記の行は単にハイレベルのモジュールやクラスが低レベルのモジュールやクラスに依存している場合、コードがタイトな結合を持っていて、1つのクラスを変更しようとすると別のクラスを壊すことができます.それは常に抽象的にクラスを緩く結合できるようにコードを抽象化することができます.これは、コードを簡単に維持することができます.
依存関係の反転が単に依存性注入を言う別の方法であるという一般的な誤解があります.しかし、2つは同じではありません.
前の例では、2つの新しいインターフェースを作成しました
以下の例で、これらのクラスを抽象化でどのように使用するかを確認できます.
我々
あなたの時間をありがとう.これは、このシリーズの終わりに私たちをもたらします.あなたが私のコンテンツを面白く見つけて、より知りたいならば、好きにしてください、そして、私に従ってください.
私は、今後数週間でさまざまなトピックの記事の多くを投稿されるので、もしあなたがこのスペースにあなたの目を更新滞在して目を離さないしないようにしたくない.
また、私のgithubに私に従うことができます.
https://github.com/Caleb-Mantey/
歓迎の人々は、あなたが今までこのシリーズを楽しんでいた願っています.これはシリーズの最終的な部分です.前の記事では、2番目と3番目の立体設計原理(オープンクローズ原理とliskov置換原理)を見ました.界面偏析原理と依存性反転である最後の2つの原理に焦点を当てた.
この記事のパート1またはパート2を読んでいない場合は、ここにアクセスできます.
https://github.com/Caleb-Mantey/solid-design-principles-in-js
今すぐ私たちのコードがどのように見えるかを要約することができます
メーラー
class Mailer{
constructor(mail, mailerFormats){
this.mail = mail
this.mailerFormats = mailerFormats
this.smtpService = new PostMarkSmtpService()
// OR this.smtpService = new SendGridSmtpService()
}
send(){
// Loops through mail formats and calls the send method
this.mailerFormats.forEach((formatter) =>
this.smtpService.send(formatter.format(this.mail)))
}
}
メールサービス
class MailerSmtpService{
constructor(smtp_connection = () => {
//connects to default smtp service
}){
this.smtp_con = smtp_connection()
}
send (mail){
this.smtp_con.send(mail)
}
}
PostMarksmtPService
class PostMarkSmtpService extends MailerSmtpService {
constructor(){
super(() => {
// Connects to postmark smtp service
})
}
send (mail){
this.smtp_con.send(mail)
}
}
SendGridDSMTPサービス
class SendGridSmtpService extends MailerSmtpService {
constructor(){
super(() => {
// Connects to sendgrid smtp service
})
}
send (mail){
this.smtp_con.deliver(mail)
}
}
HTMFormatter
class HtmlFormatter{
constructor(){
}
format(mail){
// formats to html version of mail
mail = `<html>
<head><title>Email For You</title></head>
<body>${mail}</body>
</html>`;
return mail;
}
}
テキストフォーマッタ
class TextFormatter{
constructor(){
}
format(mail){
// formats to text version of mail
mail = "Email For You \n" + mail;
return mail;
}
}
上記のコードは次のようにします.const mailer = new Mailer(“hello kwame”, [new HtmlFormatter(), new TextFormatter()])
mailer.send();
これは、我々がこの記事のパート1と2から持っていた実装です.あなたがそれを読んでいないならば、私はパート1と2を読むことを勧めます.あなたは、このテキストの冒頭に提供されるリンクを訪問することによってそうすることができます.界面分離原理
この原理は
Do not force any client to implement an interface which is irrelevant to them.
この原理は
single responsibility principle
がインターフェイスにも適用される.通常、インタフェースの第1の原理と呼ばれる.JavaScriptはインターフェイスをサポートしていないので、より良い理解を得るためにTypesScriptで実装します.最初の例を見ましょうHtmlFormatter
and TextFormatter
我々の電子メールをフォーマットして、若干の少しの変更をするクラス.フォーマッタ
export interface IFormatter {
format(mail: string): string
custom_styles(): string
}
HTMFormatter
class HtmlFormatter implements IFormatter {
format(mail: string) {
// sends html version of mail
mail = `<html>
<head>
<title>Email For You</title>
${this.custom_styles()}
</head>
<body>${mail}</body>
</html>`;
return mail;
}
custom_styles(): string {
return "<style>body{background-color: blue}</style>"
}
}
テキストフォーマッタ
class TextFormatter implements IFormatter {
format(mail: string) {
// sends text version of mail
mail = "Text Version \n" + mail;
return mail;
}
custom_styles(): string {
return ""
}
}
TypesScriptを含めて、関数の戻り値の型と変数のデータ型を宣言する必要があります.我々はまた、Cのような言語でのようなインターフェイスを作成する能力があります.この機能を使用すると、我々はインターフェイスを追加しました
IFormatter
) それは2つの機能を公開するformat
and custom_styles
). 我々TextFormatter
and HtmlFormatter
クラスもこのインターフェースの実装ですIFormatter
) メソッド.これは確かに我々はformat
and custom_styles
メソッドは両方で実装されてTextFormatter
and HtmlFormatter
クラス.If the format
and custom_styles
メソッドは、IFormatter
インターフェイス、我々のアプリケーションのエラーをスローします.しかし、ここに問題がありますcustom_styles
メソッドは、HtmlFormatter
HTMLドキュメントのスタイルを支援するクラスです.しかし両方ともTextFormatter
and HtmlFormatter
クラスは同じインターフェイスを使用しますIFormatter
) 両方とも同じメソッドを実装しなければなりません(custom_styles
and format
) 強制的に空を書くcustom_styles
メソッドTextFormatter
クラス.では、より良いアプローチを見てみましょう.
スタイル
export interface IStyles {
custom_styles(): string
}
フォーマッタ
export interface IFormatter {
format(mail: string): string
}
HTMFormatter
class HtmlFormatter implements IFormatter, IStyles {
format(mail: string) {
// sends html version of mail
mail = `<html>
<head>
<title>Email For You</title>
${this.custom_styles()}
</head>
<body>${mail}</body>
</html>`;
return mail;
}
custom_styles(): string {
return "<style>body{background-color: blue}</style>"
}
}
テキストフォーマッタ
class TextFormatter implements IFormatter {
format(mail: string) {
// sends text version of mail
mail = "Text Version \n" + mail;
return mail;
}
}
今、あなたは我々が新しいインターフェースを持っているコードrefactorから見ることができますIStyles
だけでなく、我々の前のインターフェイスIFormatter
. またHtmlFormatter
クラスはIStyles
and IFormatter
インターフェースTextFormatter
クラスはIFormatter
インターフェイス.これで、コードをクリーンにし、適切なメソッドをそれらを必要とするクラスで実装することができます.現在我々TextFormatter
クラスを実装する必要はありませんcustom_styles
メソッドを削除しましたcustom_styles
からのメソッドIFormatter
新しいインターフェイスへのインタフェースIStyles
). これにより、コードはより保守的でスケーラブルになります.これは仕事中の界面分離原理です.依存性反転原理
この原理は2つの部分に分けられ
High-level modules/classes should not depend on low-level modules/classes. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
上記の行は単にハイレベルのモジュールやクラスが低レベルのモジュールやクラスに依存している場合、コードがタイトな結合を持っていて、1つのクラスを変更しようとすると別のクラスを壊すことができます.それは常に抽象的にクラスを緩く結合できるようにコードを抽象化することができます.これは、コードを簡単に維持することができます.
依存関係の反転が単に依存性注入を言う別の方法であるという一般的な誤解があります.しかし、2つは同じではありません.
前の例では、2つの新しいインターフェースを作成しました
IStyles
and IFormatter
この関数はTextFormatter
and HtmlFormatter
クラス.以下の例で、これらのクラスを抽象化でどのように使用するかを確認できます.
メーラー
class Mailer {
mail: string;
mailerFormats: Array<IFormatter>; // abstraction
smtpService: MailerSmtpService;
constructor(mail: string, mailerFormats: Array<IFormatter>/*abstraction*/) {
this.mail = mail;
this.mailerFormats = mailerFormats;
this.smtpService = new SendGridSmtpService();
}
send() {
// Loops through mail formats and calls the send method
this.mailerFormats.forEach((formatter) =>
this.smtpService.send(formatter.format(this.mail))
);
}
}
では、次のリファクタを見てみましょうMailer
私たちの最初の例(第一原理-単一の責任原則)からのクラス.あなたは、我々が現在持っているのを見ることができますmailerFormats
配列を取得するプロパティIFormatter
オブジェクトmailerFormats: Array<IFormatter>;
). これは、IFormatter
インターフェイスをこの配列に格納できます.その他Mailer
クラスは、どのフォーマッタを使用するかを知る必要はありません.すべてが気にかけるのはフォーマッタがIFormatter
インターフェイスとformat
必要が生じたときにコールできる方法これによりMailer
私たちのクラスとゆるく結びつくクラスHtmlFormatter
and TextFormatter
クラス.我々
Mailer
クラスは抽象化に依存しますIFormatter
) のHtmlFormatter
and TextFormatter
クラス.あなたの時間をありがとう.これは、このシリーズの終わりに私たちをもたらします.あなたが私のコンテンツを面白く見つけて、より知りたいならば、好きにしてください、そして、私に従ってください.
私は、今後数週間でさまざまなトピックの記事の多くを投稿されるので、もしあなたがこのスペースにあなたの目を更新滞在して目を離さないしないようにしたくない.
また、私のgithubに私に従うことができます.
https://github.com/Caleb-Mantey/
Reference
この問題について(JavaScriptにおける立体設計原理(第3部)—界面偏析原理と依存性反転), 我々は、より多くの情報をここで見つけました https://dev.to/calebmantey/solid-design-principles-in-javascript-part-3-interface-segregation-principle-dependency-inversion-5b1iテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol