Transform View (Преобразователь)
Паттерн проектирования Transform View
Описание Transform View
Преобразует записи в HTML по одной.
Когда выполняются запросы к БД, вы получаете данные, но этого не достаточно, чтобы отобразить нормальную web-страницу. Задача вида (view) в паттерне MVC - Model View Controller - формировать данные в web-страницу. Использование Transform View подразумевает преобразование, когда на входе есть модель, а на выходе HTML.
Примеры реализации
// Transform View Pattern in JavaScript
class TransformView {
constructor() {
this.transformers = new Map();
}
registerTransformer(name, transformer) {
this.transformers.set(name, transformer);
console.log(`Transformer registered: ${name}`);
}
transform(data, transformerName) {
console.log(`Transforming data with: ${transformerName}`);
const transformer = this.transformers.get(transformerName);
if (!transformer) {
throw new Error(`Transformer not found: ${transformerName}`);
}
if (Array.isArray(data)) {
return data.map(item => transformer(item));
} else {
return transformer(data);
}
}
transformToHTML(data, transformerName) {
console.log(`Transforming to HTML with: ${transformerName}`);
const transformed = this.transform(data, transformerName);
if (Array.isArray(transformed)) {
return transformed.join('\n');
} else {
return transformed;
}
}
}
// Music album transformer
const albumTransformer = (album) => {
const artistSlug = album.artist.toLowerCase().replace(/\s+/g, '_');
const albumSlug = album.album.toLowerCase().replace(/\s+/g, '_');
return `${album.artist}`;
};
// User profile transformer
const userTransformer = (user) => {
return `
`;
};
// Product transformer
const productTransformer = (product) => {
return `
${product.name}
$${product.price.toFixed(2)}
${product.description}
`;
};
// Usage
const transformView = new TransformView();
// Register transformers
transformView.registerTransformer('album', albumTransformer);
transformView.registerTransformer('user', userTransformer);
transformView.registerTransformer('product', productTransformer);
// Sample data
const albums = [
{ artist: 'The Beatles', album: 'Abbey Road' },
{ artist: 'Pink Floyd', album: 'Dark Side of the Moon' },
{ artist: 'Led Zeppelin', album: 'Led Zeppelin IV' }
];
const users = [
{ name: 'John Doe', email: 'john@example.com', role: 'admin', joinDate: '2020-01-15' },
{ name: 'Jane Smith', email: 'jane@example.com', role: 'user', joinDate: '2021-03-20' }
];
const products = [
{ id: 1, name: 'Laptop', price: 999.99, description: 'High-performance laptop' },
{ id: 2, name: 'Mouse', price: 29.99, description: 'Wireless optical mouse' }
];
// Transform data to HTML
const albumLinks = transformView.transformToHTML(albums, 'album');
console.log('Album links generated:');
console.log(albumLinks);
const userProfiles = transformView.transformToHTML(users, 'user');
console.log('User profiles generated:');
console.log(userProfiles);
const productCards = transformView.transformToHTML(products, 'product');
console.log('Product cards generated:');
console.log(productCards);
<?php
// Transform View Pattern in PHP
class TransformView {
private $transformers = [];
public function registerTransformer($name, $transformer) {
$this->transformers[$name] = $transformer;
echo "Transformer registered: $name\n";
}
public function transform($data, $transformerName) {
echo "Transforming data with: $transformerName\n";
if (!isset($this->transformers[$transformerName])) {
throw new Exception("Transformer not found: $transformerName");
}
$transformer = $this->transformers[$transformerName];
if (is_array($data)) {
return array_map($transformer, $data);
} else {
return $transformer($data);
}
}
public function transformToHTML($data, $transformerName) {
echo "Transforming to HTML with: $transformerName\n";
$transformed = $this->transform($data, $transformerName);
if (is_array($transformed)) {
return implode("\n", $transformed);
} else {
return $transformed;
}
}
}
// Music album transformer
$albumTransformer = function($album) {
$artistSlug = strtolower(str_replace(' ', '_', $album['artist']));
$albumSlug = strtolower(str_replace(' ', '_', $album['album']));
return "<a href=\"http://example.com/music/{$albumSlug}/{$artistSlug}\">{$album['artist']}</a>";
};
// User profile transformer
$userTransformer = function($user) {
return "
<div class=\"user-profile\">
<h3>{$user['name']}</h3>
<p><strong>Email:</strong> {$user['email']}</p>
<p><strong>Role:</strong> {$user['role']}</p>
<p><strong>Join Date:</strong> " . date('Y-m-d', strtotime($user['joinDate'])) . "</p>
</div>
";
};
// Product transformer
$productTransformer = function($product) {
return "
<div class=\"product\">
<h4>{$product['name']}</h4>
<p class=\"price\">$" . number_format($product['price'], 2) . "</p>
<p class=\"description\">{$product['description']}</p>
<button onclick=\"addToCart({$product['id']})\">Add to Cart</button>
</div>
";
};
// Usage
$transformView = new TransformView();
// Register transformers
$transformView->registerTransformer('album', $albumTransformer);
$transformView->registerTransformer('user', $userTransformer);
$transformView->registerTransformer('product', $productTransformer);
// Sample data
$albums = [
['artist' => 'The Beatles', 'album' => 'Abbey Road'],
['artist' => 'Pink Floyd', 'album' => 'Dark Side of the Moon'],
['artist' => 'Led Zeppelin', 'album' => 'Led Zeppelin IV']
];
$users = [
['name' => 'John Doe', 'email' => 'john@example.com', 'role' => 'admin', 'joinDate' => '2020-01-15'],
['name' => 'Jane Smith', 'email' => 'jane@example.com', 'role' => 'user', 'joinDate' => '2021-03-20']
];
$products = [
['id' => 1, 'name' => 'Laptop', 'price' => 999.99, 'description' => 'High-performance laptop'],
['id' => 2, 'name' => 'Mouse', 'price' => 29.99, 'description' => 'Wireless optical mouse']
];
// Transform data to HTML
$albumLinks = $transformView->transformToHTML($albums, 'album');
echo "Album links generated:\n";
echo $albumLinks . "\n";
$userProfiles = $transformView->transformToHTML($users, 'user');
echo "User profiles generated:\n";
echo $userProfiles . "\n";
$productCards = $transformView->transformToHTML($products, 'product');
echo "Product cards generated:\n";
echo $productCards . "\n";
?>
// Transform View Pattern in Go
package main
import (
"fmt"
"strings"
"time"
)
type TransformView struct {
transformers map[string]func(interface{}) string
}
func NewTransformView() *TransformView {
return &TransformView{
transformers: make(map[string]func(interface{}) string),
}
}
func (tv *TransformView) RegisterTransformer(name string, transformer func(interface{}) string) {
tv.transformers[name] = transformer
fmt.Printf("Transformer registered: %s\n", name)
}
func (tv *TransformView) Transform(data interface{}, transformerName string) (interface{}, error) {
fmt.Printf("Transforming data with: %s\n", transformerName)
transformer, exists := tv.transformers[transformerName]
if !exists {
return nil, fmt.Errorf("transformer not found: %s", transformerName)
}
switch v := data.(type) {
case []interface{}:
result := make([]string, len(v))
for i, item := range v {
result[i] = transformer(item)
}
return result, nil
default:
return transformer(data), nil
}
}
func (tv *TransformView) TransformToHTML(data interface{}, transformerName string) (string, error) {
fmt.Printf("Transforming to HTML with: %s\n", transformerName)
transformed, err := tv.Transform(data, transformerName)
if err != nil {
return "", err
}
switch v := transformed.(type) {
case []string:
return strings.Join(v, "\n"), nil
case string:
return v, nil
default:
return fmt.Sprintf("%v", v), nil
}
}
// Music album transformer
func albumTransformer(data interface{}) string {
album := data.(map[string]interface{})
artist := album["artist"].(string)
albumName := album["album"].(string)
artistSlug := strings.ToLower(strings.ReplaceAll(artist, " ", "_"))
albumSlug := strings.ToLower(strings.ReplaceAll(albumName, " ", "_"))
return fmt.Sprintf("<a href=\"http://example.com/music/%s/%s\">%s</a>", albumSlug, artistSlug, artist)
}
// User profile transformer
func userTransformer(data interface{}) string {
user := data.(map[string]interface{})
name := user["name"].(string)
email := user["email"].(string)
role := user["role"].(string)
joinDate := user["joinDate"].(string)
return fmt.Sprintf(`
<div class="user-profile">
<h3>%s</h3>
<p><strong>Email:</strong> %s</p>
<p><strong>Role:</strong> %s</p>
<p><strong>Join Date:</strong> %s</p>
</div>
`, name, email, role, joinDate)
}
// Product transformer
func productTransformer(data interface{}) string {
product := data.(map[string]interface{})
id := product["id"].(int)
name := product["name"].(string)
price := product["price"].(float64)
description := product["description"].(string)
return fmt.Sprintf(`
<div class="product">
<h4>%s</h4>
<p class="price">$%.2f</p>
<p class="description">%s</p>
<button onclick="addToCart(%d)">Add to Cart</button>
</div>
`, name, price, description, id)
}
func main() {
transformView := NewTransformView()
// Register transformers
transformView.RegisterTransformer("album", albumTransformer)
transformView.RegisterTransformer("user", userTransformer)
transformView.RegisterTransformer("product", productTransformer)
// Sample data
albums := []interface{}{
map[string]interface{}{"artist": "The Beatles", "album": "Abbey Road"},
map[string]interface{}{"artist": "Pink Floyd", "album": "Dark Side of the Moon"},
map[string]interface{}{"artist": "Led Zeppelin", "album": "Led Zeppelin IV"},
}
users := []interface{}{
map[string]interface{}{"name": "John Doe", "email": "john@example.com", "role": "admin", "joinDate": "2020-01-15"},
map[string]interface{}{"name": "Jane Smith", "email": "jane@example.com", "role": "user", "joinDate": "2021-03-20"},
}
products := []interface{}{
map[string]interface{}{"id": 1, "name": "Laptop", "price": 999.99, "description": "High-performance laptop"},
map[string]interface{}{"id": 2, "name": "Mouse", "price": 29.99, "description": "Wireless optical mouse"},
}
// Transform data to HTML
albumLinks, err := transformView.TransformToHTML(albums, "album")
if err != nil {
fmt.Printf("Error transforming albums: %v\n", err)
return
}
fmt.Println("Album links generated:")
fmt.Println(albumLinks)
userProfiles, err := transformView.TransformToHTML(users, "user")
if err != nil {
fmt.Printf("Error transforming users: %v\n", err)
return
}
fmt.Println("User profiles generated:")
fmt.Println(userProfiles)
productCards, err := transformView.TransformToHTML(products, "product")
if err != nil {
fmt.Printf("Error transforming products: %v\n", err)
return
}
fmt.Println("Product cards generated:")
fmt.Println(productCards)
}
Пример: на входе преобразователя модель, содержащая имя альбома (album name) и имя артиста (artist name). На выходе - код
<a href="http://exapmle.com/music/album_name/artist_name">artist name</a>
Использована иллюстрация с сайта Мартина Фаулера.