Skip to content

Commit

Permalink
Merge pull request #11 from paulsouche/feat-examples
Browse files Browse the repository at this point in the history
  • Loading branch information
gregoryruiz authored May 15, 2017
2 parents 4c820dc + 442937f commit 6e7bc8b
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 0 deletions.
19 changes: 19 additions & 0 deletions examples/01-SRP/srp-bad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* tslint:disable:max-classes-per-file */

// Bad SRP

class UserSettings {
constructor(user) {
this.user = user;
}

public changeSettings(settings) {
if (this.verifyCredentials()) {
// ...
}
}

public verifyCredentials() {
// ...
}
}
26 changes: 26 additions & 0 deletions examples/01-SRP/srp-good.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* tslint:disable:max-classes-per-file */

// Good SRP

class UserAuth {
constructor(user) {
this.user = user;
}

public verifyCredentials() {
// ...
}
}

class UserSettings {
constructor(user) {
this.user = user;
this.auth = new UserAuth(user);
}

public changeSettings(settings) {
if (this.auth.verifyCredentials()) {
// ...
}
}
}
43 changes: 43 additions & 0 deletions examples/02-OCP/ocp-bad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* tslint:disable:max-classes-per-file */

// Bad OCP

class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = "ajaxAdapter";
}
}

class NodeAdapter extends Adapter {
constructor() {
super();
this.name = "nodeAdapter";
}
}

class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}

public fetch(url) {
if (this.adapter.name === "ajaxAdapter") {
return makeAjaxCall(url).then((response) => {
// transform response and return
});
} else if (this.adapter.name === "httpNodeAdapter") {
return makeHttpCall(url).then((response) => {
// transform response and return
});
}
}
}

function makeAjaxCall(url) {
// request and return promise
}

function makeHttpCall(url) {
// request and return promise
}
38 changes: 38 additions & 0 deletions examples/02-OCP/ocp-good.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* tslint:disable:max-classes-per-file */

// Good OCP

class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = "ajaxAdapter";
}

public request(url) {
// request and return promise
}
}

class NodeAdapter extends Adapter {
constructor() {
super();
this.name = "nodeAdapter";
}

public request(url) {
// request and return promise
}
}

class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}

public fetch(url) {
return this.adapter.request(url)
.then((response) => {
// transform response and return
});
}
}
54 changes: 54 additions & 0 deletions examples/03-LSP/lsp-bad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* tslint:disable:max-classes-per-file */

// Bad LSP

class Rectangle {
constructor() {
this.width = 0;
this.height = 0;
}

public setColor(color) {
// ...
}

public render(area) {
// ...
}

public setWidth(width) {
this.width = width;
}

public setHeight(height) {
this.height = height;
}

public getArea() {
return this.width * this.height;
}
}

class Square extends Rectangle {
public setWidth(width) {
this.width = width;
this.height = width;
}

public setHeight(height) {
this.width = height;
this.height = height;
}
}

function renderLargeRectangles(rectangles) {
rectangles.forEach((rectangle) => {
rectangle.setWidth(4);
rectangle.setHeight(5);
const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20.
rectangle.render(area);
});
}

const rectangles = [new Rectangle(), new Rectangle(), new Square()];
renderLargeRectangles(rectangles);
46 changes: 46 additions & 0 deletions examples/03-LSP/lsp-good.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* tslint:disable:max-classes-per-file */

// Good LSP

class Shape {
public setColor(color) {
// ...
}

public render(area) {
// ...
}
}

class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}

public getArea() {
return this.width * this.height;
}
}

class Square extends Shape {
constructor(length) {
super();
this.length = length;
}

public getArea() {
return this.length * this.length;
}
}

function renderLargeShapes(shapes) {
shapes.forEach((shape) => {
const area = shape.getArea();
shape.render(area);
});
}

const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];
renderLargeShapes(shapes);
25 changes: 25 additions & 0 deletions examples/04-ISP/isp-bad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Bad ISP

class DOMTraverser {
constructor(settings) {
this.settings = settings;
this.setup();
}

public setup() {
this.rootNode = this.settings.rootNode;
this.animationModule.setup();
}

public traverse() {
// ...
}
}

const $ = new DOMTraverser({
rootNode: document.getElementsByTagName("body"),
animationModule() {
// Most of the time, we won't need to animate when traversing.
},
// ...
});
33 changes: 33 additions & 0 deletions examples/04-ISP/isp-good.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Good ISP

class DOMTraverser {
constructor(settings) {
this.settings = settings;
this.options = settings.options;
this.setup();
}

public setup() {
this.rootNode = this.settings.rootNode;
this.setupOptions();
}

public setupOptions() {
if (this.options.animationModule) {
// ...
}
}

public traverse() {
// ...
}
}

const $ = new DOMTraverser({
options: {
animationModule() {
// ...
},
},
rootNode: document.getElementsByTagName("body"),
});
32 changes: 32 additions & 0 deletions examples/05-DIP/dip-bad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* tslint:disable:max-classes-per-file */

// Bad DIP

class InventoryRequester {
constructor() {
this.REQ_METHODS = ["HTTP"];
}

public requestItem(item) {
// ...
}
}

class InventoryTracker {
constructor(items) {
this.items = items;

// BAD: We have created a dependency on a specific request implementation.
// We should just have requestItems depend on a request method: `request`
this.requester = new InventoryRequester();
}

public requestItems() {
this.items.forEach((item) => {
this.requester.requestItem(item);
});
}
}

const inventoryTracker = new InventoryTracker(["apples", "bananas"]);
inventoryTracker.requestItems();
41 changes: 41 additions & 0 deletions examples/05-DIP/dip-good.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* tslint:disable:max-classes-per-file */

// Good DIP

class InventoryTracker {
constructor(items, requester) {
this.items = items;
this.requester = requester;
}

public requestItems() {
this.items.forEach((item) => {
this.requester.requestItem(item);
});
}
}

class InventoryRequesterV1 {
constructor() {
this.REQ_METHODS = ["HTTP"];
}

public requestItem(item) {
// ...
}
}

class InventoryRequesterV2 {
constructor() {
this.REQ_METHODS = ["WS"];
}

public requestItem(item) {
// ...
}
}

// By constructing our dependencies externally and injecting them, we can easily
// substitute our request module for a fancy new one that uses WebSockets.
const inventoryTracker = new InventoryTracker(["apples", "bananas"], new InventoryRequesterV2());
inventoryTracker.requestItems();

0 comments on commit 6e7bc8b

Please sign in to comment.