What are design patterns?
Design patterns are not software development jargon. In fact, “patterns” originated in architecture. In the 1970s, Harvard architecture doctoral student Christopher Alexander and his research team spent about 20 years studying different structures designed to solve the same problem, discovering similarities in high-quality designs and using the term “pattern” to refer to those similarities.
Inspired by Christopher Alexander’s work, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (known as the Gang Of Four, GoF applied this “pattern” view to object-oriented software design and summarized 23 common software development design patterns in his book design Patterns: The Foundations of Reusable Object-oriented Software.
Design patterns are simple and elegant solutions to specific problems in object-oriented software design.
Design Patterns is entirely from the perspective of object-oriented design, through the repeated use of encapsulation, inheritance, polymorphism and other techniques, extract some reusable object-oriented design techniques. But a design pattern is actually an idea for solving some problem, regardless of the language used. Design patterns still exist in functional or other programming paradigms.
Classification of design patterns
Design Patterns proposes:
Think about what might change in your design as opposed to focusing on what might lead to a redesign. It’s not about when you force a design change, it’s about how you can change it without a redesign. The key here is to encapsulate the concept of change, which is the subject of many design patterns.
Find change and encapsulate it. Design Patterns summarizes 23 design patterns. In terms of intent, these 23 design patterns can be divided into creative, structural, and behavioral patterns.
Creative design patterns
For example, the creation of an object is an abstract behavior, and what object is created can be changed. The purpose of the creation pattern is to encapsulate the changes of the creation of the object. The creative design pattern describes how to create objects. Its main feature is “the separation of object creation from use”.
Structural design mode
Structural patterns encapsulate combinatorial relationships between objects and describe how classes or objects can be arranged into a larger structure.
Behavior design pattern
Behavioral patterns encapsulate changes in the behavior of objects and describe “how classes or objects collaborate to accomplish tasks that a single object cannot accomplish alone, and how responsibilities are assigned.”
The creative design pattern in JavaScript
Although JavaScript is an object-oriented language, some of the patterns that work well for statically typed languages do not necessarily work well for JavaScript. For example, in order to emulate the JavaScript version of the Factory Method pattern, someone would awkwardness defer the creation of an object to a subclass. In statically typed languages like Java, the reason for letting subclasses “decide” what objects to create is to make the program comply with the dependency inversion principle (DIP). When creating objects in these languages, it is important to first decouple the object types so that you have a chance to make objects polymorphic in the future. In the type-fuzzy language of JavaScript, object polymorphism is inherent and there is no need to deliberately “defer” object creation to subclass creation, which means that JavaScript doesn’t actually need the factory method pattern.
Patterns exist in the first place to solve problems for us, and this kind of far-fetched simulation only makes design patterns seem obscure and useless.
1. Prototype
Brendan Eich never intended to add classes to JavaScript when he designed object-oriented systems for JavaScript.
In class-centric object-oriented programming languages, the relationship between classes and objects can be imagined as that between molds and castings, with objects always created from classes. In the idea of prototyping, classes are not necessary. Objects do not need to be created from classes. An object is created by cloning another object.
The stereotype pattern is a pattern used to create objects. If we want to create an object, one way is to specify its type and then create the object from the class. The prototype pattern takes a different approach. Instead of caring about the specific type of object, we find an object and clone it to create an identical object.
The key to the implementation of the prototype pattern is whether the language itself provides the Clone method. ECMAScript 5 provides the object. create method, which can be used to clone objects.
In fact, we don’t need to call Object.create. Every Object we encounter in JavaScript is cloned from object. prototype, which is their prototype. For example, obj1 objects and obj2 objects:
var obj1 = new Object(a);var obj2 = {};
Copy the code
In the JavaScript language, we don’t need to worry about the details of cloning, because it is implemented internally in the engine. All we need to do is explicitly call var obj1 = new Object() or var obj2 = {}. At this point, the engine will clone an Object from object. prototype internally, and this is what we get.
To get an object from a constructor using the new operator, we are familiar with the following code:
function Person( name ){
this.name = name;
};
Person.prototype.getName = function(){
return this.name;
};
var a = new Person( 'sven' )
console.log( a.name ); // Output: sven
console.log( a.getName() ); // Output: sven
console.log( Object.getPrototypeOf( a ) === Person.prototype );
Copy the code
We call new Person(), but in this case Person is not a class, but a function constructor. JavaScript functions can be called either as normal functions or as constructors. When a function is called with the new operator, the function is a constructor.
On browsers such as Chrome and Firefox that expose the __proto__ attribute of the object, we can understand the new operation by using the following code:
function Person( name ){
this.name = name;
};
Person.prototype.getName = function(){
return this.name;
};
var objectFactory = function(){
var obj = new Object(), // Clone an empty Object from Object.prototype
Constructor = [].shift.call( arguments ); // Get the constructor passed in from the outside, in this case Person
obj.__proto__ = Constructor.prototype; // Point to the correct prototype
var ret = Constructor.apply( obj, arguments ); // Use the constructor passed in from the outside to set properties for obj
return typeof ret === 'object' ? ret : obj; // Make sure the constructor always returns an object
};
var a = objectFactory( Person, 'sven' );
console.log( a.name ); // Output: sven
console.log( a.getName() ); // Output: sven
console.log( Object.getPrototypeOf( a ) === Person.prototype ); // Output: true
Copy the code
One thing we know about prototypes is that when an object cannot respond to a request, it passes the request along the prototype chain until it finds an object that can handle the request.
2. Singleton
The singleton pattern guarantees that a class has only one instance and provides a global access point to access it.
Imagine if you wanted to click a button to pop up the login popover. We have two ways to do it, the first one is created at the beginning, but display is None, and we make it visible when we click on it. Second, we listen for click events, dynamically generate nodes, and add them to the DOM.
In the first case, some people click on a web page just to look around, not to log in, and if pop-ups are designed from the start, they may waste a few DOM nodes. For the second, one thing to note is that for repeated clicks, the popover should not be generated repeatedly. No matter how many times the button is clicked, the popover should only be created once, which is suitable for singleton mode.
const getSingle = (fn) = > {
let result;
return (. rest) = > {
return result || (result = fn.apply(this, rest))
}
}
const createLoginLayer = () = > {
const div = document.createElement('div');
div.innerHTML = "Landing popover";
div.style.display = 'none';
document.appendChild(div);
return div
}
const createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById('loginBtn').onclick = () = > {
const loginLayer = createSingleLoginLayer();
loginLayer.style.display = 'block';
}
Copy the code
The createSingleLoginLayer function makes use of closures to ensure that the node is only created the first time, and for repeated clicks, only the first node is returned each time.
The resources
Design Patterns: The Foundation of Reusable Object-oriented Software JavaScript Design Patterns and Development Practices 23 Design Patterns — Creative Design Patterns Learning JavaScript Design Patterns