Transform View (Преобразователь)

Паттерн проектирования 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>

Использована иллюстрация с сайта Мартина Фаулера.

Источник