Understand the Decorator pattern by comparing JavaScript and Java code

Introduction

Details and other patterns will be written in ** Understanding design patterns by comparing implementations in JavaScript and Java **. I wrote an example of JavaScript by looking at Java. We do not take advantage of differences in features such as class type / prototype type, typed strength, and access modifiers. Please note.

Decorator There is one sponge cake, cream shortcake, and strawberry shortcake If you apply chocolate, it becomes a chocolate cake The objects are similar, there is a sponge cake-like object at the center, and the decoration function is covered with each skin to finish it as an object that suits the purpose. Such a design pattern that decorates objects more and more decorator means "decorate"

ファイル 2017-01-29 .png

Implementation in Java

Class diagram

Decorator2.png

code

Main.java


public class Main {
    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello, world.");
        Display b2 = new SideBorder(b1, '#');
        Display b3 = new FullBorder(b2);
        b1.show();
        b2.show();
        b3.show();
        Display b4 = 
            new SideBorder(
                new FullBorder(
                    new FullBorder(
                        new SideBorder(
                            new FullBorder(
                                new StringDisplay("Hello.")
                            )
                        , '*')
                    )
                )
            , '/');
        b4.show();
    }
}

Deisplay.java


public abstract class Display {
    public abstract int getColumns();
    public abstract int getRows();
    public abstract String getRowText(int row);
    public final void show() {
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}

StringDisplay.java


public class StringDisplay extends Display {
    private String string;
    public StringDisplay(String string) {
        this.string = string;
    }
    public int getColumns() {
        return string.getBytes().length;
    }
    public int getRows() {
        return 1;
    }
    public String getRowText(int row) {
        if (row == 0) {
            return string;
        } else {
            return null;
        }
    }
}

Border.java


public abstract class Border extends Display{
    protected Display display;
    protected Border(Display display) {
        this.display = display;
    }
}

SideBorder.java


public class SideBorder extends Border {
    private char borderChar;
    public SideBorder(Display display, char ch) {
        super(display);
        this.borderChar = ch;
    }
    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {
        return display.getRows();
    }
    public String getRowText(int row) {
        return borderChar + display.getRowText(row) + borderChar;
    }
}

FullBorder.java


public class FullBorder extends Border {
    public FullBorder(Display display) {
        super(display);
    }
    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {
        return 1 + display.getRows() + 1;
    }
    public String getRowText(int row) {
        if (row == 0) {
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else if (row == display.getRows() + 1) {
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else {
            return "|" + display.getRowText(row - 1) + "|";
        }
    }
    private String makeLine(char ch, int count) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}

JavaScript ** * I don't know if it's a console specification, but if you insert a 2-byte one, the layout will collapse **

code

index.html


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Decorator</title>
</head>
<body>
    <script src="Main.js"></script>
    <script src="StringDisplay.js"></script>
    <script src="SideBorder.js"></script>
    <Script src="FullBorder.js"></script>
    <script src="Display.js"></script>
</body>
</html>

Main.js


MAIN = {};
MAIN.init = function() {
    var b1 = new StringDisplay("Hello world.");
    var b2 = new SideBorder(b1, '#');
    var b3 = new FullBorder(b2);
    b1.show();
    b2.show();
    b3.show();
    var b4 = 
        new SideBorder(
            new FullBorder(
                new FullBorder(
                    new SideBorder(
                        new FullBorder(
                            new StringDisplay("Hello")
                        ), '*'
                    )
                )
            ), '/'
        );
    b4.show();
};


window.addEventListener("load", MAIN.init);

StringDisplay.js


var StringDisplay = function(string) {
    this.string = string;
};


StringDisplay.prototype = {
    constructor: "StringDisplay",

    getColumns: function() {
        return this.getBytes(this.string);
    },
    getRows: function() {
        return 1;
    },
    getRowText: function(row) {
        if (row == 0) {
            return this.string;
        } else {
            return null;
        }
    },
    getBytes: function(str) {
        var len = 0;
        str = escape(str);
        for (i = 0; i < str.length; i++, len++) {
            if (str.charAt(i) == "%") {
                if (str.charAt(++i) == "u") {
                    i += 3;
                    len++
                }
                i++;
            }
        }
        return len;
    }
};

SideBorder.js


var SideBorder = function(display, ch) {
    this.display = display;
    this.borderChar = ch;
};

SideBorder.prototype = {
    constructor: "SideBorder",

    getColumns: function() {
        return 1 + this.display.getColumns() + 1;
    },
    getRows: function() {
        return this.display.getRows();
    },
    getRowText(row) {
        return this.borderChar + this.display.getRowText(row) + this.borderChar;
    }
}

FullBorder.js


var FullBorder = function(display) {
    this.display = display;
};

FullBorder.prototype = {
    constructor: "FullBorder",

    getColumns: function() {
        return 1 + this.display.getColumns() + 1;
    },
    getRows: function() {
        return 1 + this.display.getRows() + 1;
    },
    getRowText: function(row) {
        if (row == 0) {
            return "+" + this.makeLine('-', this.display.getColumns()) + "+";
        } else if (row == this.display.getRows() + 1) {
            return "+" + this.makeLine('-', this.display.getColumns()) + "+";
        } else {
            return "|" + this.display.getRowText(row - 1) + "|";
        }
    },
    makeLine: function(ch, count) {
        var stringBuffer = "";
        for (var i = 0; i < count; i++) {
            stringBuffer += '-';
        }
        return stringBuffer;
    }
}

Display.js


StringDisplay.prototype.show = 
SideBorder.prototype.show = 
FullBorder.prototype.show = function() {
    for (var i = 0; i < this.getRows(); i++) {
        console.log(this.getRowText(i));
    }
};

Characters in the Decorator pattern

** Role of Component **

Core role when adding features Define only the interface (API) Sample program ⇒ Display (class)

** The role of ConcreateComponent **

Implements the interface (API) that plays the role of Component Sample program ⇒ StringDisplay (class)

** The role of Decorator **

Implements the interface (API) that plays the role of Component And have a Component role Sample program ⇒ Border (class)

** The role of Concreate Decorator **

Specific decorator role Sample program ⇒ SideBorder (class)           FullBorder(class)

Decorator pattern class diagram

Decorator.png

The need for a Decorator pattern

By using the Decorator pattern, you can create a lot of concrete Concreate Decorator roles and combine them to create different types of objects. And it is also a feature that functions can be added without changing the contents, and functions can be added dynamically.

When using the Decorator pattern

It is similar to Composite in that it can handle recursive structures and can be identified, but the purpose is different. Composite has a recursive structure inside Decorator has a recursive structure on the outside

Compositeと比較.PNG

Related patterns

reference

[Introduction to Design Patterns Learned in the Enhanced and Revised Java Language](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82% E7% 89% 88Java% E8% A8% 80% E8% AA% 9E% E3% 81% A7% E5% AD% A6% E3% 81% B6% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3% 83% B3% E5% 85% A5% E9% 96% 80-% E7% B5 % 90% E5% 9F% 8E-% E6% B5% A9 / dp / 4797327030)

Recommended Posts

Understand the Decorator pattern by comparing JavaScript and Java code
Understand the Strategy pattern by comparing JavaScript and Java code
Understand the State pattern by comparing JavaScript and Java code
Understand the Composite pattern by comparing JavaScript and Java code
Understand design patterns by comparing implementations in JavaScript and Java [Updated from time to time]
Decorator pattern in Java
Try to implement and understand the segment tree step by step (python)
Learn the design pattern "Decorator" in Python
Java compilation and execution understood by CLI
Read the file by specifying the character code.
Understand the Decision Tree and classify documents