ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScriptを深く理解するシリーズ(8) S.O.L.I.D五原則 - リスコフ置換原則 LSP_javascriptスキル

JavaScriptを深く理解するシリーズ(8) S.O.L.I.D五原則 - リスコフ置換原則 LSP_javascriptスキル

WBOY
リリース: 2016-05-16 17:57:02
オリジナル
1401 人が閲覧しました

はじめに
この章で説明するのは、S.O.L.I.D JavaScript 言語実装の 5 つの原則のうちの 3 つ目、Liskov Substitution Principle LSP (The Liskov Substitution Principle) です。

英語原文: http://freshbrewedcode.com/derekgreer/2011/12/31/solid-javascript-the-liskov-substitution-principle/
コードをコピー
冒頭の説明そして最後の原則は次のとおりです。

サブタイプはその基本型に対して置換可能である必要があります。
派生型はその基本型に対して置換可能である必要があります。
コードをコピー
オブジェクト指向プログラミングでは、継承により、サブクラスが基本クラスのコードを共有するメカニズムが提供されます。これは、共通のデータと動作を基本型にカプセル化し、型を宣言することで実現されます。より詳細なサブタイプについては、リスコフ置換原則を適用するために、継承されたサブタイプが基本タイプの望ましい動作と意味的に同等である必要があります。

理解を深めるために、次のコードを参照してください。

コードをコピーします コードは次のとおりです。

関数 Vehicle(my) {
var my = my ||
my.running = false; >this.speed = function() {
return my.speed;
this.start = function() {
my.running = true; this.stop = function() {
my.running = false;
this.accelerate = function() {
my.speed;
; decelerate = function () {
my.speed--;
}, this.state = function() {
if (!my.running) {
return "parked"; }
else if (my.running && my.speed) {
return "moving";
}
else if (my.running) {
return "idle"; }
};
}


上記のコードでは Vehicle 関数を定義しており、そのコンストラクターは Vehicle オブジェクトに対していくつかの基本的な操作を提供します。現在サービスで実行中 お客様の製品環境で、車両の動作を高速化するために新しいコンストラクターを追加する必要がある場合。考えた結果、次のコードを書きました:




コードをコピー


コードは次のとおりです:


function FastVehicle (my) {

すべての機能は期待通りで、問題ありません。は3倍に増加しており、彼から受け継いだメソッドは予想どおりに機能します。その後、この新しいバージョンのクラス ライブラリを実稼働環境にデプロイし始めましたが、新しいコンストラクターを受け取ったため、既存のコードは実行をサポートできなくなりました。次のコード スニペットは、この問題を明らかにしています:



コードをコピー


コードは次のとおりです:

var 操作 = function(vehicle) {
write(vehicle) .state() );
vehicle.state());
write(vehicle.state()); >write(vehicle.speed()); vehicle.decelerate(); if (vehicle.state() != "idle") { throw "車両はまだ動いています!" vehicle.stop(); ;
According to the above code, we see that the exception thrown is "The vehicle is still moving!" This is because the author who wrote this code always believed that the numbers of acceleration and deceleration are the same. . But FastVehicle code and Vehicle code are not completely replaceable. Therefore, FastVehicle violates the Liskov substitution principle.

At this point, you may be thinking: "However, the client cannot always assume that vehicles are done according to such rules", the Liskov Substitution Principle (LSP) hinders (Translator's Note: That is Code that prevents implementation of LSP) is not based on what we think inherited subclasses should do to ensure updated code in behavior, but whether such updates can be implemented within current expectations.

In the case of the above code, to solve this incompatibility problem requires a little redesign in the vehicle class library or client calling code, or both.

Reduce LSP obstruction
So, how do we avoid LSP obstruction? Unfortunately, this is not always possible. We have a few strategies here for how we deal with this.

Contracts
One strategy to deal with LSP excessive obstruction is to use contracts. Contract lists come in two forms: executable specifications and error handling. In the executable specifications, a detailed class library The contract also includes a set of automated tests, and error handling is handled directly in the code, such as in preconditions, postconditions, constant checks, etc. You can view this technology from Bertrand Miller's masterpiece "Contract Design". Although automated testing and contract design are beyond the scope of this article, I still recommend the following when we use them:

Check out using Test-Driven Development to guide the design of your code
Feel free to use contract design techniques when designing reusable class libraries
For the code you want to maintain and implement yourself, using contract design tends to add a lot of unnecessary code. If you want to control input, adding tests is very useful. It is essential that, if you are a class library author using contract design, you should be aware of incorrect usage and allow your users to use it as a testing tool.

Avoid inheritance
Another test to avoid LSP hindrance is: if possible, try not to inherit. In Gamma's masterpiece "Design Patterns – Elements of Reusable Object-Orineted Software", we can see The following suggestions:

Favor object composition over class inheritance
Try to use object composition over class inheritance
Copy code
Some books discuss that the only role that composition is better than inheritance is static typing. For class-based languages ​​(i.e., behavior that can be changed at runtime), one issue related to JavaScript is coupling. When using inheritance, inherited subtypes are coupled to their base types, which means that changes to the type will Affects inherited subtypes. Composition tends to make objects smaller and easier to maintain in both static and dynamic languages.

It’s about behavior, not inheritance
So far, we’ve discussed the Liskov substitution principle with inheritance context, which dictates JavaScript’s object-oriented reality. However, the essence of Liskov Substitution Principle (LSP) is not really about inheritance, but about behavioral compatibility. JavaScript is a dynamic language. The contract behavior of an object is not determined by the type of the object, but by the expected function of the object. The Liskov substitution principle was originally conceived as a principle guide for inheritance, equivalent to the implicit interface in object design.

For example, let’s take a look at a rectangle type from Robert C. Martin’s masterpiece "Agile Software Development Principles, Patterns, and Practices":

Rectangle Example
Consider us There is a program that uses a rectangular object like the following:
Copy the code The code is as follows:

var rectangle = {
length: 0,
width: 0
};
[code]
After that, the program needs a square, because a square is a length (length) and a width ( width) are the same special rectangle, so we think of creating a square instead of the rectangle. We added length and width properties to match the declaration of a rectangle, but we feel that using the property's getters/setters we can synchronize the length and width saves to ensure that a square is declared:
[code]
var square = {};
(function() {
var length = 0, width = 0;
// Note that the defineProperty method is a new feature of version 262-5
Object.defineProperty(square, " length", {
get: function() { return length; },
set: function(value) { length = width = value; }
});
Object.defineProperty(square, "width", {
get: function() { return width; },
set: function(value) { length = width = value; }
});
})();

Unfortunately, we found a problem when we used a square instead of a rectangle to execute the code. One of the methods to calculate the area of ​​a rectangle is as follows:
Copy code The code is as follows:

var g = function(rectangle) {
rectangle.length = 3;
rectangle.width = 4;
write(rectangle .length);
write(rectangle.width);
write(rectangle.length * rectangle.width);
};

When this method is called, the result is 16 instead of the expected 12. Our square square object violates the LSP principle. The length and width properties of square imply that it is not 100% compatible with rectangles, but we do not always imply this explicitly. To solve this problem, we can redesign a shape object to implement the program. Based on the concept of polygon, we declare rectangle and square, relevant. Anyway, our purpose is to say that the Liskov Substitution Principle is not just inheritance, but any method (in which the behavior can be another behavior).

Summary
The Liskov Substitution Principle (LSP) expresses not the inheritance relationship, but any method (as long as the behavior of the method can reflect the behavior of another).
関連ラベル:
lsp
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート