To come in
All computer secrets for beginners and professionals
  • How to remove adware virus on your computer
  • Step-by-step guide - how to connect to a computer anywhere in the world for free
  • How to reinstall Windows: step-by-step instructions How long does it take to reinstall Windows 7
  • How to change the password on a PC or laptop In contact, change the password without a phone
  • World of Tanks test server World of tanks test server opens
  • World of Tanks test server When will the world of tank test be available
  • Js design patterns. Wp.template - HTML templates for Javascript in WordPress. Types of Design Patterns

    Js design patterns.  Wp.template - HTML templates for Javascript in WordPress.  Types of Design Patterns

    In this article we will cover common design patterns in JS. These patterns offer developers ways to solve technical problems in reusable and elegant ways. Want to improve your JavaScript skills? Then read on.

    What is a design pattern or pattern?

    Simply put, a design pattern is a reusable software solution to a specific type of problem that often arises in software development. Over many years of software development practice, experts have figured out ways to solve such problems. These decisions were encapsulated in design patterns.

    • templates are proven solutions to software development problems
    • templates are scalable because they are usually structured and have rules that you must adhere to
    • templates can be reused for similar tasks

    Types of Design Patterns

    In software development, design patterns are usually grouped into several categories. In this article, we will look at the three most important ones.

    Briefly about them:

    1. Creational patterns focus on the way objects or classes are created. This may seem simple (and in some cases it is), but large applications must control the object creation process.
    2. Structural design patterns focus on managing the relationships between objects so that your application is built in a scalable way. A key aspect of the structural model is to ensure that a change in one part of the application does not affect all other parts.
    3. Behavioral patterns focus on connections between objects

    A note about classes in JavaScript

    When reading about design patterns, you will often see references to classes and objects. This can get confusing because JavaScript doesn't actually use “class”; the more correct term is “data type”.

    JavaScript Data Types

    JavaScript is an object-oriented language where objects inherit from other objects, in a concept known as prototypical inheritance. Data types can be created by defining what is called a “constructor function”, for example:

    Function Person(config) ( this.name = config.name; this.age = config.age; ) Person.prototype.getAge = function() ( return this.age; ); var tilo = new Person((name:"Tilo", age:23 )); console.log(tilo.getAge());

    Note the use of prototype when defining methods on the Person data type. Since multiple Person objects will reference the same prototype, this will allow the getAge() method to be shared by all instances of the Person data type, rather than overriding it on a per-instance basis. Additionally, any data type that inherits from Person will have access to the getAge() method.

    Working with privacy

    Another common problem with JavaScript is that it doesn't have any private variables. But, we can use multiple closures to simulate privacy. Consider the following snippet:

    Var retinaMacbook = (function() ( //Private variables var RAM, addRAM; RAM = 4; //Private methods addRAM = function (additionalRAM) ( RAM += additionalRAM; ); return ( //Public variables and USB methods: undefined , insertUSB: function (device) ( this.USB = device; ), removeUSB: function () ( var device = this.USB; this.USB = undefined; return device; ) ); ))();

    In the example above, we created a retinaMacbook object, with public and private variables and methods. Here's how we'll use it:

    RetinaMacbook.insertUSB("myUSB"); console.log(retinaMacbook.USB); //logs out "myUSB" console.log(retinaMacbook.RAM) //logs out undefined

    Generative patterns

    There are many different kinds of spawning patterns (abstract factory, builder, factory method, lazy initialization, singleton pool, object pool, prototype, resource acquisition is initialization, singleton), but in this tutorial, we'll only look at two of them: Builder and Prototype. They are used often enough to earn attention.

    Builder pattern

    The building pattern is often used in web development, and you've probably used it before without realizing it. Simply put, this pattern can be defined as follows:

    Using a construction template allows you to build objects by specifying only the type and content of the object. There is no need to create an object.

    For example, you've probably done this countless times in jQuery:

    Var myDiv = $("

    This is a div.
    "); //myDiv now represents a jQuery object referencing a DOM node. var someText = $("

    "); //someText is a jQuery object referencing HTMLParagraphElement var input = $(" ");

    Take a look at the three examples above. In the first of them, we went to

    an element with some content. In the second, we went to an empty tag

    In the last one, we went to element. The result of all three was the same - we were returned a jQuery object referencing the DOM node.

    The $ variable adapts the jQuery building pattern. In each example, we were returned a jQuery DOM object and had access to all the methods provided by the jQuery library, and at no point did we call document.createElement. The JS library handled all of this behind closed doors.

    Imagine how much work it would be if we had to create a DOM element and insert content into it! By using a construction pattern, we can focus our attention on the type and content of the object rather than on its explicit creation.

    Prototype pattern

    Previously, we looked at the process of defining data types in JavaScript through functions and adding methods to an object's prototype. Prototype patterns (schemas) allow objects to inherit from other objects through their prototypes.

    A prototype template is a template in which objects are created from the template of an existing object by cloning.

    This is a simple and natural way to implement inheritance in JavaScript. For example:

    Var Person = (numFeet: 2, numHeads: 1, numHands:2); //Object.create takes its first argument and applies it to the prototype of the new object. var tilo = Object.create(Person); console.log(tilo.numHeads); //result 1 tilo.numHeads = 2; console.log(tilo.numHeads) //result 2

    The properties (and methods) in the Person object are applied to the tilo object's prototype. We can override the properties of the tilo object if we want them to be different.

    In the above example, we used Object.create(). However, Internet Explorer 8 does not support the new method. In these cases we can imitate its behavior:

    Var vehiclePrototype = ( init: function (carModel) ( this.model = carModel; ), getModel: function () ( console.log("The model of this vehicle is " + this.model); ) ); function vehicle (model) ( function F() (); F.prototype = vehiclePrototype; var f = new F(); f.init(model); return f; ) var car = vehicle("Ford Escort"); car.getModel();

    Structural patterns

    Structural patterns are really useful, especially when figuring out how a system should work. They allow applications to easily scale and remain manageable. From this considerable group (adapter, bridge, linker, decorator, facade, single entry point, opportunist, proxy), we will consider the following models: Composer and Facade.

    Linker (design pattern)

    • The Composer pattern is another type of pattern that you've probably used without realizing it.

    So what does this mean? Let's take a look at the following example in jQuery (most JS libraries will have equivalents to this):

    $(".myList").addClass("selected"); $("#myItem").addClass("selected"); //Don't do this on large tables, this is just an example. $("#dataTable tbody tr").on("click", function(event)( alert($(this).text()); )); $("#myButton").on("click", function(event) ( alert("Clicked."); ));

    Most JavaScript libraries provide a consistent API, regardless of whether we are dealing with a single DOM element or an array of DOM elements. In the first example, we can add a selected class to all elements matched by the .myList selector, but we can also use the same method when it comes to a single DOM element, #myItem. Similarly, you can attach an event handler using the on() method on multiple nodes, or on a single node via the same API.

    By using composite layouts, jQuery (and many other libraries) provide us with a simplified API.

    The Composite template can sometimes cause problems. In a loosely coded language like JavaScript, it's useful to know whether we're dealing with a single element or multiple elements. Since the template builder uses the same API for both, we can often mistake one for the other and end up with an unexpected error. Some libraries, such as YUI3, offer two separate methods for retrieving elements (Y.one() vs Y.all()).

    Facade (design pattern)

    Here's another pattern we take for granted. An object that abstracts the work with several classes, combining them into a single whole.

    The facade pattern provides the user with a simple interface, hiding its main complexities.

    A façade pattern almost always improves the usability of a piece of software. Using jQuery as an example, one of the most common library methods is the ready() method:

    $(document).ready(function() ( //all your code goes here... ));

    The ready() method actually implements the facade. If you look at the source, here's what you'll find:

    Ready: (function() ( ... //Mozilla, Opera, and Webkit if (document.addEventListener) ( document.addEventListener("DOMContentLoaded", idempotent_fn, false); ... ) //IE event model else if ( document.attachEvent) ( // ensure firing before onload; may be late, but safe for iframes document.attachEvent("onreadystatechange", idempotent_fn); // Fallback for window.onload, which always works window.attachEvent("onload", idempotent_fn); ... ) ))

    The ready() method is not that simple. jQuery normalizes browser volatility so that ready() fires at the right time. However, as a developer, you will be presented with a simple interface.

    Most examples of façade templates follow this principle. To implement it, we usually rely on conditional statements, but present it as a simple interface for the user. Other methods for implementing this pattern include animate() and css().

    Behavioral patterns

    Any object-oriented software system will have relationships between objects. Failure to organize such connections can lead to errors that are difficult to find and correct. Behavioral design patterns prescribe various methods for organizing communication between objects (chain of responsibility, command, interpreter, iterator, mediator, custodian, observer, servant, specification, state, strategy, template method, visitor, etc.). In this section, we will look at the Observer and Mediator patterns.

    Observer template

    This is what is said about the Observer:

    In the observer pattern, an object can have a list of observers that are interested in its lifecycle. Any time an object does something interesting, it sends a notification to its observers. If the observer is no longer interested in listening to an object, then he can remove it from his list.

    We need three methods to describe this pattern:

    publish(data): Called by an object when it has a notification. Some data can be transferred using this method.
    subscribe(observer): Called by an object to add an observer to its list of observers.
    unsubscribe(observer): Called by an object to remove an observer from the list of observers.
    Most modern JavaScript libraries support these three methods as part of their event infrastructure. Typically there is an on() or attach() method, a trigger() or fire() method, and an off() or detach() method. Consider the following snippet:

    //We simply create a connection between jQuery event methods var o = $(()); $.subscribe = o.on.bind(o); $.unsubscribe = o.off.bind(o); $.publish = o.trigger.bind(o); // Usage document.on("tweetsReceived", function(tweets) ( //perform some actions, then fire an event $.publish("tweetsShow", tweets); )); //We can subscribe to this event and then fire our own event. $.subscribe("tweetsShow", function() ( //display the tweets somehow .. //publish after it is shown $.publish("tweetsDisplayed); )); $.subscribe("tweetsDisplayed, function() (...));

    The observer pattern is one of the simplest patterns to implement, and very powerful. JavaScript is well suited to adopt this pattern because it itself is event-based. Next time you're developing web applications, consider developing modules that are loosely coupled and adopt the Observer pattern as a means of communication. The observer pattern can become problematic if too many objects and observers are involved.

    Template Mediator

    The last pattern we will look at is the Mediator. It is similar to the Observer pattern, but with some notable differences.

    An intermediary facilitates the use of one common object that establishes a connection with several objects. All objects interact with each other through an intermediary.

    In the world of software development, the mediator pattern is used when a system becomes too complex. By placing intermediaries, communication can occur through a single entity, instead of multiple entities communicating with each other. In this sense, the mediator can be used to replace the system that implements the observer patterns.
    Let's talk about how you can use it. Imagine that you have a web application that allows users to click on an album and play music from it. You can create a mediator like this:

    $("#album").on("click", function(e) ( e.preventDefault(); var albumId = $(this).id(); mediator.publish("playAlbum", albumId); )) ; var playAlbum = function(id) ( … mediator.publish("albumStartedPlaying", (songList: [..], currentSong: "Without You")); ); var logAlbumPlayed = function(id) ( //Login album on the Benend); var updateUserInterface = function(album) ( //Update the UI to display what's playing); //Mediator subscriptions mediator.subscribe("playAlbum", playAlbum); mediator.subscribe("playAlbum", logAlbumPlayed); mediator.subscribe("albumStartedPlaying", updateUserInterface);

    The advantage of this pattern is that one object is responsible for communication, while in an observer pattern, multiple objects can listen and subscribe to each other.
    In the observer pattern, there is not a single object that contains restrictions. Instead, the observer and subject must cooperate to maintain the constraint. Communication patterns are determined by the ways in which observers and subjects are interrelated: one subject usually has many observers, and sometimes the observer of one subject is the subject of another observer.

    Conclusion

    The great thing about design patterns is that someone has already used them successfully in the past. There is a lot of open-source code that implements various patterns in JavaScript. As developers, we need to be aware of what patterns are out there and when to apply them.

    Translation ()
    Photo source - Fotolia.ru

    Hello, habr!
    I was surprised to find that there was no detailed article about the subject on Habré, which immediately prompted me to correct this blatant injustice.

    In an environment where the client side of web applications is becoming increasingly thick, business logic is inexorably creeping onto the client, and node.js is increasingly encroaching on the sovereignty of server technologies, one cannot help but think about the techniques of designing architecture in JavaScript. And in this matter, design patterns should undoubtedly help us - template methods for solving frequently encountered problems. Patterns help you build an architecture that requires the least amount of effort from you when changes need to be made. But you should not perceive them as a panacea, i.e., roughly speaking, if the quality of the code is “not great”, it is teeming with hard code and tight connections between logically independent modules, then no patterns will save it. But if the task is to design a scalable architecture, then patterns can be a good help.
    However, this article is not about design patterns as such, but about their application in javaScript. In the first part of this article I will write about the use of generative patterns.

    Singleton

    If the task was to describe this pattern in one phrase, it would turn out something like this: Singleton is a class that can have only one instance.
    The simplest and most obvious JavaScript solution for implementing this pattern is to use objects:

    Var app = ( property1: "value", property2: "value", ... method1: function () ( ... ), ... )

    This method has both its advantages and disadvantages. It is easy to describe, many people use it without realizing the existence of any patterns, and this form of writing will be understandable to any JavaScript developer. But it also has a significant drawback: the main purpose of the singleton pattern is to provide access to an object without using global variables, and this method provides access to the app variable only in the current scope. This means that we can access the app object from anywhere in the application only if it is global. Most often this is extremely unacceptable; good JavaScript development style is to use at most one global variable, which encapsulates everything needed. This means that we can use the above approach at most once in the application.
    The second method is a little more complicated, but also more universal:

    Function SomeFunction () ( if (typeof (SomeFunction.instance) == "object") ( return SomeFunction.instance; ) this.property1 = "value"; this.property2 = "value"; SomeFunction.instance = this; return this ; ) SomeFunction.prototype.method1 = function () ( )

    Now, using any modular system (for example, requirejs), we can connect a file with a description of this constructor function anywhere in our application and get access to our object by executing:

    Var someObj = new SomeFunction();

    But this method also has its drawback: the instance is stored simply as a static property of the constructor, which allows anyone to overwrite it. We want that, under any circumstances, we can access the required object from any corner of our application. This means that the variable in which we will save the instance must be made private, and closures will help us with this.

    Function SomeFunction () ( var instance; SomeFunction = function () ( return instance; ) this.property1 = "value"; this.property2 = "value"; instance = this; )

    It would seem that this is the solution to all problems, but new problems take the place of old ones. Namely: all properties included in the constructor prototype after the instance is created will not be available, because in fact, they will be written to the old constructor, and not to the newly defined one. But there is a decent way out of this situation:

    Function SomeFunction () ( var instance; SomeFunction = function () ( return instance; ) SomeFunction.prototype = this; instance = new SomeFunction (); instance.constructor = SomeFunction; instance.property1 = "value"; instance.property2 = " value"; return instance; )

    This method of describing a singleton is devoid of all the above disadvantages and is quite suitable for universal use, however, methods of describing a singleton using a closure will not work with requirejs, but if you modify them a little and move the variable out of the closure created by the function itself into the function used in define, then the problem will be solved:

    Define(, function () ( var instance = null; function SomeFunction() ( if (instance) ( return instance; ) this.property1 = "value"; this.property2 = "value"; instance = this; ); return SomeFunction ; ));

    Factory method

    The factory method has two main goals:
    1) Don't use explicitly concrete classes
    2) Combine commonly used object initialization methods together
    The simplest implementation of a factory method is this example:

    Function Foo () ( //... ) function Bar () ( //... ) function factory (type) ( switch (type) ( case "foo": return new Foo(); case "bar": return new Bar(); ) )

    Accordingly, the creation of objects will look like this:

    Foo = factory("foo"); bar = factory("bar");

    A more elegant solution can be used:

    Function PetFactory() ( ); PetFactory.register = function(name, PetConstructor) ( if (name instanceof Function) ( PetConstructor = name; name = null; ) if (!(PetConstructor instanceof Function)) ( throw ( name: "Error", message: "PetConstructor is not function" ) ) this = PetConstructor; ); PetFactory.create = function(petName) ( var PetConstructor = this; if (!(PetConstructor instanceof Function)) ( throw ( name: "Error", message: "constructor "" + petName + "" undefined" ) ) return new PetConstructor (); );

    In this case, we do not limit ourselves to the number of classes that the factory can generate; we can add as many of them as we like in this way:

    PetFactory.register("dog", function() ( this.say = function () ( console.log("gav"); ) ));

    Or like this:

    Function Cat() ( ) Cat.prototype.say = function () ( console.log("meow"); ) PetFactory.register(Cat);

    Abstract Factory

    An abstract factory is used to create a group of interconnected or interdependent objects.
    Suppose we have several pop-up windows that consist of the same elements, but these elements look different and react differently to user actions. Each of these elements will be created using a factory method, which means that each type of pop-up window needs its own object factory.
    For example, let's describe the BluePopupFactory factory; it has exactly the same structure as PetFactory, so we'll omit the details and just use it.

    Function BluePopup () ( //creating a popup window) BluePopup.prototype.attach = function (elemens) ( //attaching other ui elements to the window) BluePopupFactory.register("popup", BluePopup); function BluePopupButton () ( //creating a button for a blue popup window) BluePopupButton.prototype.setText = function (text) ( //setting the text on the button) BluePopupFactory.register("button", BluePopupButton); function BluePopupTitle () ( //creating a title for the blue window) BluePopupTitle.prototype.setText = function (text) ( //setting the title text) BluePopupFactory.register("title", BluePopupTitle);

    We should probably have some kind of class responsible for interface elements.

    Function UI () ( //class responsible for ui elements)

    And we will add the createPopup method to it:

    UI.createPopup = function (factory) ( var popup = factory.create("popup"), buttonOk = factory.create("button"), buttonCancel = factory.create("button"), title = factory.create(" title"); buttonOk.setText("OK"); buttonCancel.setText("Cancel"); title.setText("Untitled"); popup.attach(); )

    As you can see, createPopup takes a factory as an argument, creates the popup itself and buttons with a title for it, and then attaches them to the window.
    After that you can use this method like this:

    Var newPopup = UI.createPopup(BluePopupFactory);

    Accordingly, you can describe an unlimited number of factories and pass the one you need when creating the next pop-up window.

    Sometimes it is not desirable to instantiate a class directly. Then we resort to generative patterns, which can select the optimal instantiation mechanism.

    Simple Factory

    Making doors yourself when building a house would be quite difficult, so you get them ready-made from the store.

    Pattern A simple factory produces the required copy without bothering the client with the intricacies of this process.

    Implementation example

    Let's create an implicit interface for all doors:

    /* Door getWidth() getHeight() */ class WoodenDoor ( constructor(width, height)( this.width = width this.height = height ) getWidth() ( return this.width ) getHeight() ( return this.height ) )

    We will organize a factory that will produce them:

    Const DoorFactory = ( makeDoor: (width, height) => new WoodenDoor(width, height) )

    That's it, you can work:

    Const door = DoorFactory.makeDoor(100, 200) console.log("Width:", door.getWidth()) console.log("Height:", door.getHeight())

    The pattern is useful if creating an object requires some logic. It makes sense to move repetitive code into a separate Simple Factory.

    Factory method

    A recruiting manager works with candidates for various vacancies. Instead of delving into the intricacies of each position, he delegates the technical interview to fellow specialists.

    This pattern allows you to create different variations of an object without polluting the constructor with unnecessary code.

    Implementation example

    Let's start with the hamburger itself:

    Class Burger ( constructor(builder) ( this.size = builder.size this.cheeze = builder.cheeze || false this.pepperoni = builder.pepperoni || false this.lettuce = builder.lettuce || false this.tomato = builder .tomato || false ) )

    And here is the Builder:

    Class BurgerBuilder ( constructor(size) ( this.size = size ) addPepperoni() ( this.pepperoni = true return this ) addLettuce() ( this.lettuce = true return this ) addCheeze() ( this.cheeze = true return this ) addTomato() ( this.tomato = true return this ) build() ( return new Burger(this) ) )

    Voila! Here's our burger:

    Const burger = (new BurgerBuilder(14)) .addPepperoni() .addLettuce() .addTomato() .build()

    The Builder pattern is needed if an object can exist in different variations or the instantiation process consists of several steps.

    Singleton

    The country must have a single president, otherwise there will be chaos.

    This pattern wraps an object and dynamically changes its behavior.

    Implementation example

    Let's take coffee for example. The simplest coffee that implements the appropriate interface:

    /* Coffee interface: getCost() getDescription() */ class SimpleCoffee( getCost() ( return 10 ) getDescription() ( return "Simple coffee" ) )

    We want to be able to add various additives to coffee, for this we will create some decorators:

    Class MilkCoffee ( constructor(coffee) ( this.coffee = coffee ) getCost() ( return this.coffee.getCost() + 2 ) getDescription() ( return this.coffee.getDescription() + ", milk" ) ) class WhipCoffee ( constructor(coffee) ( this.coffee = coffee ) getCost() ( return this.coffee.getCost() + 5 ) getDescription() ( return this.coffee.getDescription() + ", whip" ) ) class VanillaCoffee ( constructor (coffee) ( this.coffee = coffee ) getCost() ( return this.coffee.getCost() + 3 ) getDescription() ( return this.coffee.getDescription() + ", vanilla" ) )

    Now you can make coffee to your taste:

    Let someCoffee someCoffee = new SimpleCoffee() console.log(someCoffee.getCost())// 10 console.log(someCoffee.getDescription())// Simple Coffee someCoffee = new MilkCoffee(someCoffee) console.log(someCoffee.getCost( ))// 12 console.log(someCoffee.getDescription())// Plain coffee, milk someCoffee = new WhipCoffee(someCoffee) console.log(someCoffee.getCost())// 17 console.log(someCoffee.getDescription() )// Plain coffee, milk, cream someCoffee = new VanillaCoffee(someCoffee) console.log(someCoffee.getCost())// 20 console.log(someCoffee.getDescription())// Plain coffee, milk, cream, vanilla

    Facade

    To turn on the computer, just press a button. It's very simple, but there's a lot of complex stuff going on inside the computer that turns on. A simple interface to a complex system is the Façade.

    Implementation example

    Let's create a computer class:

    Class Computer ( getElectricShock() ( console.log("Ouch!") ) makeSound() ( console.log("Beep beep!") ) showLoadingScreen() ( console.log("Loading..") ) bam() ( console.log("Ready to be used!") ) closeEverything() ( console.log("Bup bup bup buzzzz!") ) sooth() ( console.log("Zzzzz") ) pullCurrent() ( console. log("Haaah!") ) )

    and a simple Façade for its complex functions:

    Class ComputerFacade ( constructor(computer) ( this.computer = computer ) turnOn() ( this.computer.getElectricShock() this.computer.makeSound() this.computer.showLoadingScreen() this.computer.bam() ) turnOff() ( this.computer.closeEverything() this.computer.pullCurrent() this.computer.sooth() ) )

    This makes working with a computer much easier:

    Const computer = new ComputerFacade(new Computer()) computer.turnOn() // Ouch! Beep beep! Loading.. Ready to be used! computer.turnOff() // Bup bup buzzz! Haah! Zzzzz

    Opportunist

    On long-distance trains, water for hot drinks is boiled in large containers - for everyone at once. This allows you to save electricity (or gas).

    On job search sites you can subscribe to job options that interest you. When a suitable offer appears, the site sends you a notification.

    The Observer pattern allows you to notify all interested objects about changes that have occurred.

    Implementation example

    Applicants want to receive notifications:

    Const JobPost = title = (( title: title )) class JobSeeker ( constructor(name) ( this._name = name ) notify(jobPost) ( console.log(this._name, "has been notified of a new posting:", jobPost.title) ) )

    And the Notice Board can send these notifications:

    Class JobBoard ( constructor() ( this._subscribers = ) subscribe(jobSeeker) ( this._subscribers.push(jobSeeker) ) addJob(jobPosting) ( this._subscribers.forEach(subscriber = ( subscriber.notify(jobPosting) )) ) )

    // create subscribers const jonDoe = new JobSeeker("John Doe") const janeDoe = new JobSeeker("Jane Doe") const kaneDoe = new JobSeeker("Kane Doe") // create a message board // sign up applicants const jobBoard = new JobBoard() jobBoard.subscribe(jonDoe) jobBoard.subscribe(janeDoe) // notify subscribers about a new vacancy jobBoard.addJob(JobPost("Software Engineer")) // John Doe has been notified of a new posting: Software Engineer // Jane Doe has been notified of a new posting: Software Engineer

    Visitor

    To travel abroad, you need to obtain permission (visa). But once in the country, you can safely visit a variety of places without asking for additional permission. You just need to know about them.

    The Visitor pattern allows you to add additional operations to objects without changing their source code.

    Implementation example

    Let's simulate a zoo with different types of animals:

    Class Monkey ( shout() ( console.log("Ooh oo aa aa!") ) accept(operation) ( operation.visitMonkey(this) ) class Lion ( roar() ( console.log("Roaaar!") ) accept(operation) ( operation.visitLion(this) ) ) class Dolphin ( speak() ( console.log("Tuut tuttu tuutt!") ) accept(operation) ( operation.visitDolphin(this) ) )

    Now we want to listen to what sounds they make. To do this, we will create a Visitor:

    Const speak = ( visitMonkey(monkey)( monkey.shout() ), visitLion(lion)( lion.roar() ), visitDolphin(dolphin)( dolphin.speak() ) )

    It simply accesses each class and calls the desired method:

    Const monkey = new Monkey() const lion = new Lion() const dolphin = new Dolphin() monkey.accept(speak) // Ooh oo aa aa! lion.accept(speak) // Roaaar! dolphin.accept(speak) // Tuut tutt tuutt!

    The visitor allows existing objects not to be modified. With its help, you can, for example, add the ability to jump to all these animals without creating additional methods.

    Const jump = ( visitMonkey(monkey) ( console.log("Jumped 20 feet high! on to the tree!") ), visitLion(lion) ( console.log("Jumped 7 feet! Back on the ground!") ) , visitDolphin(dolphin) ( console.log("Walked on water a little and disappeared") ) )

    Monkey.accept(speak) // Ooh oo aa aa! monkey.accept(jump) // Jumped 20 feet high! on to the tree! lion.accept(speak) // Roaaar! lion.accept(jump) // Jumped 7 feet! Back on the ground! dolphin.accept(speak) // Tuut tutt tuutt! dolphin.accept(jump) // Walked on water a little and disappeared

    Strategy

    To organize some set of data, you use a bubble sort algorithm. It copes well with small volumes, but slows down with large ones. Quicksort has the opposite problem. Then you decide to change the algorithm depending on the size of the set. This is your Strategy.

    The Strategy template allows you to switch the algorithm used depending on the situation.

    Implementation example

    First-class functions will help you implement the Strategy in JavaScript.

    Const bubbleSort = dataset => ( console.log("Sorting with bubble sort") // ... // ... return dataset ) const quickSort = dataset => ( console.log("Sorting with quick sort") / / ... // ... return dataset )

    And this is a client who can use any strategy:

    Const sorter = dataset => ( if(dataset.length > 5)( return quickSort ) else ( return bubbleSort ) )

    Now you can sort the arrays:

    Const longDataSet = const shortDataSet = const sorter1 = sorter(longDataSet) const sorter2 = sorter(shortDataSet) sorter1(longDataSet) // Sorting with quick sort sorter2(shortDataSet) // Sorting with bubble sort

    State

    You draw in Paint. Depending on your choice, the brush changes its state: it paints in red, blue or any other color.

    The State pattern allows you to change the behavior of a class when the state changes.

    Implementation example

    Let's create a text editor in which you can change the state of the text - bold, italic, etc.

    These are the conversion functions:

    Const upperCase = inputString => inputString.toUpperCase() const lowerCase = inputString => inputString.toLowerCase() const defaultTransform = inputString => inputString

    And here is the editor himself:

    Class TextEditor ( constructor(transform) ( this._transform = transform ) setTransform(transform) ( this._transform = transform ) type(words) ( console.log(this._transform(words)) ) )

    You can work:

    Const editor = new TextEditor(defaultTransform) editor.type("First line") editor.setTransform(upperCase) editor.type("Second line") editor.type("Third line") editor.setTransform(lowerCase) editor.type ("Fourth line") editor.type("Fifth line") // First line // SECOND LINE // THIRD LINE // fourth line // fifth line

    Template method

    You build a house according to a specific plan: first the foundation, then the walls and only then the roof. The order of these steps cannot be changed, but their implementation may vary.

    A template method defines the "skeleton" of the algorithm, but delegates the implementation of the steps to child classes.

    Implementation example

    Let's create a tool for testing, building and deploying the application.

    The base class defines the skeleton of the assembly algorithm:

    Class Builder ( // Template method build() ( this.test() this.lint() this.assemble() this.deploy() ) )

    And the child classes are the specific implementation of each step:

    Class AndroidBuilder extends Builder ( test() ( console.log("Running android tests") ) lint() ( console.log("Linting the android code") ) assemble() ( console.log("Assembling the android build" ) ) deploy() ( console.log("Deploying android build to server") ) ) class IosBuilder extends Builder ( test() ( console.log("Running ios tests") ) lint() ( console.log("Linting the ios code") ) assemble() ( console.log("Assembling the ios build") ) deploy() ( console.log("Deploying ios build to server") ) )

    Let's assemble the project:

    Const androidBuilder = new AndroidBuilder() androidBuilder.build() // Running android tests // Linting the android code // Assembling the android build // Deploying android build to server const iosBuilder = new IosBuilder() iosBuilder.build() // Running ios tests // Linting the ios code // Assembling the ios build // Deploying ios build to server

    Every developer strives to write convenient and easy to read code. As applications get larger, structuring the code becomes an important part.
    Design patterns play an important role in this task by providing an organizational structure for common issues in specific circumstances.
    When creating applications, web developers JavaScript often interact with design patterns unconsciously.

    They tend to use some design patterns more than others, although there is an extensive list of design patterns for different cases.

    In this post I would like to discuss common patterns to improve your programming knowledge and dive deeper into JavaScript.

    Design patterns include the following:

    — Module

    — Prototype

    — Observer

    — Loner

    Each template consists of many properties, but I highlight the following key points:

    1.Context: Where/under what circumstances is this or that pattern used?

    2. Problem: What problem are we trying to solve?

    3. Solution: How can I use this pattern to solve this problem?

    4.Implementation: What does the implementation look like?

    # Template Module (Module)

    In JavaScript, modules are the most common design pattern for making parts of code independent from other components. This provides loose coupling to maintain well-structured code.
    For those familiar with object-oriented languages, modules are "classes" V JavaScript. One of the many benefits of classes is encapsulation—protecting state and behavior from access from other classes.
    The module pattern gives access to public and private levels (plus less secure and privileged ones).

    This language UML describes a prototype interface used to clone specific implementations.

    To clone an object, there must be a constructor to instantiate the first object. Next, using the keyword prototype Variables and methods are bound to the structure of the object. Let's look at a simple example:

    var TeslaModelS = function() ( this.numWheels = 4; this.manufacturer = "Tesla"; this.make = "Model S"; ) TeslaModelS.prototype.go = function() ( // The wheels are spinning ) TeslaModelS.prototype. stop = function() ( )

    This. numWheels = 4 ;

    This. make = "Model S" ;

    TeslaModelS. prototype. go = function() (

    // The wheels are spinning

    TeslaModelS. prototype. stop = function () (

    // Brake pads are applied

    The constructor allows you to create a single object TeslaModelS. When creating a new object TeslaModelS, it will save the state initialized in the constructor. In addition, maintaining the function go And stop easy, since we declared them using prototypes. The same way to extend a function using a prototype is described below:

    var TeslaModelS = function() ( this.numWheels = 4; this.manufacturer = "Tesla"; this.make = "Model S"; ) TeslaModelS.prototype = ( go: function() ( // Wheels are spinning), stop: function() ( // Brake pads are applied ) )

    var TeslaModelS = function () (

    This. numWheels = 4 ;

    This. manufacturer = "Tesla" ;

    This. make = "Model S" ;

    TeslaModelS. prototype = (

    Go:function()(

    // The wheels are spinning

    Stop : function () (

    // Brake pads are applied

    REVEALING PROTOTYPE PATTERN

    Just like the template module, the prototype template has a variation Revealing. Revealing the pattern provides encapsulation with public and private members.

    Since we are returning an object, we will prefix the prototype object with a function. Expanding on our example, we can choose what we want to show in the current prototype to preserve our access levels:

    var TeslaModelS = function() ( this.numWheels = 4; this.manufacturer = "Tesla"; this.make = "Model S"; ) TeslaModelS.prototype = function() ( var go = function() ( // Wheels turn ); var stop = function() ( // Brake pads are applied ); return ( pressBrakePedal: stop, pressGasPedal: go ) )();

    var TeslaModelS = function () (

    This. numWheels = 4 ;

    This. manufacturer = "Tesla" ;

    This. make = "Model S" ;

    TeslaModelS. prototype = function() (

    Var go = function() (

    // The wheels are spinning

    } ;

    Var stop = function () (

    // Brake pads are applied

    } ;

    Return (

    PressBrakePedal: stop,

    PressGasPedal: go

    } () ;

    Please note how the functions Stop And Go will be protected from the returned object due to being outside the scope of the returned object. Because the JavaScript natively supports prototypical inheritance, there is no need to rewrite basic elements (or features or traits).

    # Observer Template (Observer)

    It happens that one part of the application changes, and other parts need updating. IN Angular j s if $scope object is updated, an event can be fired to notify another component. The Observer pattern includes that if the object is modified, then it passes (broadcasts) dependent objects that the change has occurred.

    Another prime example is the Model-View-Controller (MVC) architecture; the view is updated when the model changes. One advantage is decoupling the view from the model to reduce dependencies.

    As shown in the UML diagram, the required objects are subject, observer, And concrete. An object subject contains links to concrete observers to notify you of any changes. An object observer is an abstract class that allows concrete observers implement the notification method.

    Let's look at an example AngularJS, which includes the Observer pattern through event management.

    // Controller 1 $scope.$on("nameChanged", function(event, args) ( $scope.name = args.name; )); ... // Controller 2 $scope.userNameChanged = function(name) ( $scope.$emit("nameChanged", (name: name)); );

    // Controller 1

    $scope. $ on ("nameChanged" , function ( event , args ) (

    $scope. name = args. name ;

    } ) ;

    . . .

    // Controller 2

    $scope. userNameChanged = function (name) (

    $scope. $emit("nameChanged", (name:name));

    With template Observer it is important to distinguish whether it is an independent object or subject .

    It is important to note that although the template Observer and provides many advantages, but one of the disadvantages is a significant drop in performance, since the number of “observers” ( observers) increased. One of the most notorious observers is watchers . IN AngularJS We can observe ( watch) variables, functions and objects. Cycle $$digest works and notifies each of watchers new values ​​whenever the object's area changes.

    We can create our own Subjects And Observers V JavaScript. Let's see how this is implemented:

    var Subject = function() ( this.observers = ; return ( subscribeObserver: function(observer) ( this.observers.push(observer); ), unsubscribeObserver: function(observer) ( var index = this.observers.indexOf(observer) ; if(index > -1) ( this.observers.splice(index, 1); ) ), notifyObserver: function(observer) ( var index = this.observers.indexOf(observer); if(index > -1) ( this.observers.notify(index); ) ), notifyAllObservers: function() ( for(var i = 0; i< this.observers.length; i++){ this.observers[i].notify(i); }; } }; }; var Observer = function() { return { notify: function(index) { console.log("Observer " + index + " is notified!"); } } } var subject = new Subject(); var observer1 = new Observer(); var observer2 = new Observer(); var observer3 = new Observer(); var observer4 = new Observer(); subject.subscribeObserver(observer1); subject.subscribeObserver(observer2); subject.subscribeObserver(observer3); subject.subscribeObserver(observer4); subject.notifyObserver(observer2); // Observer 2 is notified! subject.notifyAllObservers(); // Observer 1 is notified! // Observer 2 is notified! // Observer 3 is notified! // Observer 4 is notified!

    var Subject = function() (

    This. observers = ;

    Return (

    SubscribeObserver: function (observer) (

    This. observers. push(observer);

    } ,

    UnsubscribeObserver: function (observer) (

    If (index & gt ; - 1 ) (

    This. observers. splice(index, 1);

    } ,

    NotifyObserver: function (observer) (

    Var index = this . observers. indexOf(observer);

    If (index & gt ; - 1 ) (

    This. observers[index]. notify(index);

    } ,

    NotifyAllObservers : function () (

    For (var i = 0 ; i & lt ; this . observers . length ; i ++ ) (

    This. observers[i]. notify(i);

    } ;

    } ;

    var Observer = function() (

    Return (

    Notify: function (index) (

    Console. log("Observer " + index + " is notified!" ) ;

    var subject = new Subject();

    var observer1 = new Observer();

    var observer2 = new Observer();

    Even though we can write anything in JavaScript, this can lead to problems if we use the wrong design patterns or implement the required pattern incorrectly.

    Developers tend to use the latest frameworks and libraries to create web applications, combining two or more of them into one project, and often forgetting the basic ideas behind creating these libraries.

    Design patterns are similar to architectural drawings in that they show how to solve a software development problem correctly and quickly. They are structured using best practices that help ensure the stability and, in many cases, security of our web applications. Because the JavaScript is not a traditional object-oriented programming language, defining design patterns in it may be a little difficult, but not impossible.

    In this article, we will discuss various design patterns and how we can best implement them. For brevity we we will only talk about the five most used templates.

    Types of Design Patterns

    There are many design patterns in software development. These patterns are grouped under three groups, which we will briefly review below:

    Generative patterns: These patterns focus on the way objects are created. When creating objects in large applications, there is always a tendency to complicate things. Using generative design patterns solves this problem by controlling the creation of an object.

    Structural patterns: Structural patterns provide ways to manage relationships between objects and also create the structure of classes. One way to achieve this is to use inheritance and composition to create a large object from small objects.

    Behavioral patterns: Behavioral patterns are patterns that focus on interactions between objects. While generative patterns describe a point in time and structural patterns describe a more or less static structure, behavioral patterns describe a process or flow.

    Creating a template module

    A module is very often used in software development, and it is an expression consisting of a function that is immediately executed.

    // and here we have the code

    All module code exists in a private scope. Variables are imported by passing values, and exported by executing a function that returns an object. Modules are useful in large systems because they help keep your global namespace clean and also keep your functions importable and exportable.

    An example of an implemented module is shown below:

    Const options = (
    username: "Michail",
    host: "site"
    };

    Const Configuration = (function(params) (

    // returns publicly available data

    Return (
    login:login
    };

    Const username = params.username \|\| "",
    server = params.server \|\| "",
    password = params.password \|\| "";

    Function checkPass()
    {
    if (this.password === "") (
    alert("no password!");
    return false;
    }

    Return true;
    }

    Function checkUsrname()
    {

    If (this.username === "")
    {
    alert("no username!");
    return false;
    }

    Return true;
    }

    Function login()
    {
    if (checkPass() && checkUsrname())
    {
    // perform authorization
    }
    }

    ))(options);

    Note that the username, hostname, and password values ​​are continually imported and exported. Using modules provides a clean architecture that will make your code more readable and less buggy.