(See the previous (and first) iteration.)
Now, I have incorporated all the modifications proposed by janos, and, thus, I have the following:
HtmlViewComponent.java
package net.coderodde.html.view;
/**
* This abstract class defines the API for logical HTML view components, that
* may consist of other view components;
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public interface HtmlViewComponent {
public String toHtml();
}
HtmlViewContainer.java
package net.coderodde.html.view;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* This class defines the API for HTML elements that may contain other HTML
* elements.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public abstract class HtmlViewContainer implements HtmlViewComponent {
protected final List<HtmlViewComponent> components = new ArrayList<>();
public void addHtmlViewComponent(HtmlViewComponent component) {
Objects.requireNonNull(component, "The input component is null.");
components.add(component);
}
public boolean containsHtmlViewComponent(HtmlViewComponent component) {
Objects.requireNonNull(component, "The input component is null.");
return components.contains(component);
}
public void removeHtmlViewComponent(HtmlViewComponent component) {
Objects.requireNonNull(component, "The input component is null.");
components.remove(component);
}
}
HtmlPage.java
package net.coderodde.html.view;
/**
* This class is the top-level container of view components.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public class HtmlPage extends HtmlViewContainer {
private final String title;
public HtmlPage(String title) {
this.title = title != null ? title : "";
}
@Override
public String toHtml() {
StringBuilder sb = new StringBuilder().append("<!DOCTYPE html>\n")
.append("<html>\n")
.append("<head>\n")
.append("<title>")
.append(title)
.append("</title>\n")
.append("</head>\n")
.append("<body>\n");
components.stream().forEach((component) -> {
sb.append(component.toHtml());
});
return sb.append("</body>\n")
.append("</html>").toString();
}
}
DivComponent.java
package net.coderodde.html.view.support;
import net.coderodde.html.view.HtmlViewContainer;
/**
* This class implements a {@code div} component.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public class DivComponent extends HtmlViewContainer {
@Override
public String toHtml() {
StringBuilder sb = new StringBuilder("<div>\n");
components.stream().forEach((component) -> {
sb.append(component.toHtml());
});
return sb.append("</div>\n").toString();
}
}
TableComponent.java
package net.coderodde.html.view.support;
import java.util.ArrayList;
import java.util.List;
import net.coderodde.html.view.HtmlViewComponent;
/**
* This class represents the table component.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public class TableComponent implements HtmlViewComponent {
private final int columns;
public TableComponent(int columns) {
checkColumnNumber(columns);
this.columns = columns;
}
private final List<List<? extends HtmlViewComponent>> table = new ArrayList<>();
public void addRow(List<HtmlViewComponent> row) {
if (row.size() > columns) {
table.add(new ArrayList<>(row.subList(0, columns)));
} else {
table.add(new ArrayList<>(row));
}
}
private void checkColumnNumber(int columns) {
if (columns <= 0) {
throw new IllegalArgumentException(
"The number of columns must be a positive integer. " +
"Received " + columns);
}
}
@Override
public String toHtml() {
StringBuilder sb = new StringBuilder().append("<table>\n");
for (List<? extends HtmlViewComponent> row : table) {
sb.append("<tr>");
for (HtmlViewComponent cell : row) {
sb.append("<td>");
sb.append(cell.toHtml());
sb.append("</td>");
}
// Deal with the missing table cells at the current row.
for (int i = row.size(); i < columns; ++i) {
sb.append("<td></td>");
}
sb.append("</tr>\n");
}
return sb.append("</table>\n").toString();
}
}
TextComponent.java
package net.coderodde.html.view.support;
import net.coderodde.html.view.HtmlViewComponent;
/**
* This class represents a simple text.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Mar 18, 2016)
*/
public class TextComponent implements HtmlViewComponent {
private String text;
public TextComponent() {
this("");
}
public TextComponent(String text) {
setText(text);
}
public void setText(String text) {
this.text = text != null ? text : "";
}
public String getText() {
return text;
}
@Override
public String toHtml() {
return text;
}
}
Demo.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.coderodde.html.view.HtmlPage;
import net.coderodde.html.view.HtmlViewComponent;
import net.coderodde.html.view.support.DivComponent;
import net.coderodde.html.view.support.TableComponent;
import net.coderodde.html.view.support.TextComponent;
public class Demo {
public static void main(String[] args) {
HtmlPage page = new HtmlPage("FUNKEEH PAGE");
DivComponent div1 = new DivComponent();
DivComponent div2 = new DivComponent();
div1.addHtmlViewComponent(new TextComponent("Hey yo!\n"));
TableComponent table = new TableComponent(3);
// Arrays.asList is immutable, so copy to a mutable array list.
List<HtmlViewComponent> row1 = new ArrayList<>(
Arrays.asList(new TextComponent("Row 1, column 1"),
new TextComponent("Row 1, column 2"),
new TextComponent("Row 1, column 3"),
new TextComponent("FAIL")));
List<HtmlViewComponent> row2 = new ArrayList<>(
Arrays.asList(new TextComponent("Row 2, column 1"),
new TextComponent("Row 2, column 2")));
table.addRow(row1);
table.addRow(row2);
div2.addHtmlViewComponent(table);
div2.addHtmlViewComponent(new TextComponent("Bye, bye!\n"));
page.addHtmlViewComponent(div1);
page.addHtmlViewComponent(div2);
System.out.println(page.toHtml());
}
}
Please, tell me anything that comes to mind.