Подскажите какой использовать паттерн

krafty

new Exception
Подскажите какой использовать паттерн

Кратко опишу ситуацию.

Есть класс A, реализующий паттерн компоновщик. При создании объекта класса A и его инициализации происходят ресурсоемкие операции.

Далее этот объект используется для получения определенного результата.
В процессе проектирования выяснилось, что объект класса A должен использоваться в еще одной ситуации для получения другого результата, основываясь на тех же исходных данных + некоторые дополнительные данные.

Использование объекта во второй ситуации привнесет изменение в инициализацию и добавит специфичные для ситуации методы.

С одной стороны необходимо разделить API по решаемым задачам, чтобы не концентрировать все в одном классе.
С другой стороны нельзя допускать повторной инициализации громоздкого объекта.

Как правильно будет поступить в этом случае? Есть ли идеологическая необходимость в выделении нового класса. Если есть, то какой шаблон проектирования можно применить.
 

findnext

Новичок
невнимательно прочитал топик, посему удаляю свой коммент

-~{}~ 08.04.09 13:19:

krafty
ты б хоть какую нибудь схему чтоли нарисовал...чего то слишком как то мало написал. Если нужны паттерны проектирования то вот ссылка
http://phpclub.ru/talk/showthread.php?threadid=56263&rand=2

-~{}~ 08.04.09 13:20:

ооо вот, тут похожая тема была

http://phpclub.ru/talk/showthread.php?s=&threadid=56936&rand=5
 

krafty

new Exception
спасибо. гляну

-~{}~ 08.04.09 15:39:

Как промежуточный вариант размышлений:
- реализация класса А (на диаграмме SQL_Tree) включает в себя все варианты использования - это недостаток
- Builder (абстрактный) создает и инициализирует объект SQL_Tree
- потомки (Select и Update) могут переопределять метод build_tree
- объект SQL_Tree в классе Builder статический

Преимущества: возможность переопределения инициализации и однократная инициализация сложного объекта

Немного UML для наглядности


-~{}~ 08.04.09 17:43:

небольшое замечание:
в родительской реализации приходится делать проверку в методе built_tree(), чтобы не проходила повторная инициализация статического объекта SQL_Tree при вызове в потомке

PHP:
protected function build_tree() {

  if (self::$is_init) return;
  
  // object initialization...

}
 

fixxxer

К.О.
Партнер клуба
У меня одного при вопросе "какой использовать паттерн" возникает немотивированная агрессия в адрес вопрошающего?
 

krafty

new Exception
Автор оригинала: fixxxer
У меня одного при вопросе "какой использовать паттерн" возникает немотивированная агрессия в адрес вопрошающего?
и чем вызвана?
 

findnext

Новичок
krafty
а зачем создавать сразу огромный объект? почему нельзя наполнять его постепенно?

-~{}~ 09.04.09 00:16:

мне кажется это большой ошибкой
 

krafty

new Exception
Автор оригинала: findnext
а зачем создавать сразу огромный объект? почему нельзя наполнять его постепенно?
извини, не совсем понятно, что значит "наполнять его постепенно"
объект наполняется в методе build_tree() постепенно в foreach ;)
 

findnext

Новичок
krafty
другими словами, нельзя разделить build_tree на части или вообще убрать? и добавлять всё в дерево только по мере необходимости?

-~{}~ 09.04.09 11:53:

иными словами без использования foreach...
 

krafty

new Exception
findnext
надо подумать над этим. хотя подозреваю, что если это будет возможно, то непременно повлечет за собой мощные изменения в коде.

проблему повторной инициализации я решил. только вот не удается разделить логику в самом классе SQL_Tree.

Фактически существует базовый блок инициализации SQL_Tree - который должен выполняться в любом случае.
Другие блоки инициализации уже отличаются от специфики задач (построение SELECT запроса или UPDATE запроса, например). Эта специфика в свою очередь требует дополнительного API со стороны SQL_Tree
 

krafty

new Exception
класс представляет собой набор уникальных цепочек-связей между таблицами БД в виде дерева.

PHP:
/**
 * Class represents tree from unique SQL_Path nodes.
 *
 */
class Generator_SQL_Tree {
	
	/**
	 * @var boolean
	 */
	private $is_root = false;

       /**
	 * Generator_SQL_Node_Table object
	 *
	 * @var Generator_SQL_Node_Table
	 */
	private $object_node;
	
	/**
	 * Array of children
	 *
	 * @var array
	 */
	private $children = array();
	
	/**
	 * Parent tree node
	 *
	 * @var Generator_SQL_Tree
	 */
	private $parent;
	
	/**
         * Link to parent tree node
         *
         * @var Generator_SQL_Link
         */
        private $link2parent;
	
	/**
	 * Table alias counter
	 *
	 * @var integer
	 */
	private $table_occurced;
	
	/**
	 * @var string
	 */
	private $name;
	
	/**
	 * Class constructor
	 *
	 * @param integer $level tree level; root has "0" level
	 * @param Generator_SQL_Node_Table $object_node
	 * @param Generator_SQL_Tree $parent
	 */
	public function __construct($object_node=NULL,$parent=NULL) {
		

		
	}
		
	/**
	 * Adds child to current tree object
	 *
	 * @param Generator_SQL_Tree $object_tree
	 */
	public function addChild(Generator_SQL_Tree $object_tree) {

		$this->children[] = $object_tree;

	}		
	
	/**
	 * @return array
	 */
	public function getChildren() {
		return $this->children;
	}
		
	/**
	 * @return boolean
	 */
	public function isRoot() {
		return $this->is_root;
	}
	
	/**
	 * @return Generator_SQL_Tree
	 */
	public function getParent() {
		return $this->parent;
	}
	
	/**
	 * @return string
	 */
	public function getName() {
		return $this->name;
	}
		
	/**
	 * @return Generator_SQL_Link
	 */
	public function getLink2Parent() {
		return $this->link2parent;
	}

	
}

?>
-~{}~ 09.04.09 11:22:

код с реального проекта, поэтому в примере кода есть несколько классов, о которых я не говорил. если будет необходимость, объясню назначение

-~{}~ 09.04.09 11:26:

наполнение класса происходит путем добавления sql цепочек. при этом анализируются связи между узлами цепочки, чтобы дерево содержало только уникальные цепочки.
 

krafty

new Exception
метод build_sql_tree проходится по всем цепочкам, полученным от парсера и вызывает add_to_tree для каждой цепочки.

PHP:
<?php

/**
 * Abstract base class for build SQL queries from SQLPath equations.
 */
abstract class Generator_SQL_Builder {
           
    /**
     * Table's SQL tree.
     * @var Generator_SQL_Tree
     */
    protected static $object_tree_root;
      
    /**
     * Tree built flag.
     * @var boolean
     */
    private static $is_tree_built = false;
    
    /**
     * Parse process complemented flag.
     * @var boolean
     */
    private static $is_parsed = false;
    
    /**
     * Tables frequency of occurrences array.
     * @var array
     */
    private $arr_tables_occurced;
    
    /**
     * Class constructor.
     * Creating parser object.
     * Creating SQL tree object.
     * @param array|string $table_sqlpath
     * @param array $field_sqlpath
     */
    public function __construct($table_sqlpath,$field_sqlpath,$where_parts = array()) {

        //....................
    	
        // creating tree root
        self::$object_tree_root = new Generator_SQL_Tree(); // tree root
        
        // build tree
        $this->build_sql_tree();
        
    }
    
    /**
     * Runs parse process.
     * Method can be overrides for run
     * additional parse process, e.g. {@link Generator_SQL_Sources::parse_where()}.
     */
    protected function run_parser() {
    	
    	if (self::$is_parsed) return ;
    	
        self::$object_sources->parse_fields();
        
        // parsed flag
        self::$is_parsed = true;
    	
    }
    
    /**
     * Building SQL tree.
     * Method can be overrides for adding
     * additional build logic.
     */
    protected function build_sql_tree() {
        
    	if (self::$is_tree_built) return ;
    	
        // adding nodes from fields to tree
        /* @var $template Generator_SQL_Template */
        foreach (self::$object_sources->getFields() as $template) {
	        /* @var $node Generator_SQL_Node_Table */
        	foreach ($template->getFields() as $node) {
        		$this->add_to_tree($node);
                        // вот здесь отличия: при построении UPDATE запроса эта часть не нужна
	        	// adding grouping field to the tree
	        	if ($node->getGroupNode()) {
	        		$this->add_to_tree($node->getGroupNode());
	        	}
        	}
        }
        
        self::$is_tree_built = true;        
        
    }
    
    /**
     * @param Generator_SQL_Node_Abstract $node full path
     */
    protected function add_to_tree($node) {
    	                                                                                                              
    	$tree = self::$object_tree_root;
    	
    	/* @var $child Generator_SQL_Tree */
    	while ($node instanceof Generator_SQL_Node_Abstract) {
    		  
                // если узла еще не существует в дереве, то добавляем его  		
    		if (false === ($child_to_add = $tree->getChildByNode($node))) {
    			
	    		// correcting aliases counter
	    		$this->setTableFrequency($node->getItemName());
	    		// create node
	    		$child_to_add = new Generator_SQL_Tree($node,$tree);
	    		// set table counter
	    		$child_to_add->setTableOccurced($this->getTableFrequency($node->getItemName()));
	    		// adding new node to tree
	    		$tree->addChild($child_to_add);
	    			    		
	    	}
	    	
	    	$node = $node->getNextNode();
	    	
	    	$tree = $child_to_add;
            
            // вот здесь отличия: при построении SELECT запроса эта часть не нужна
            // if node is representing the field - add it to tree child
            if ($node instanceof Generator_SQL_Node_Field) {
                $tree->addField($node);
                break;
            }
	    	
    	}
    	
    }    
	
	/**
	 * @return boolean
	 */
	public static function isTreeBuilt() {
		
		return self::$is_tree_built;
		
	}
	
	/**
	 * @return boolean
	 */
	public static function isParsed() {
		
		return self::$is_parsed;
		
	}
    
}
-~{}~ 09.04.09 11:49:

производные от этого классы переопределяют build_sql_tree для добавления своей логики. повторной инициализации препятствует статический флаг is_tree_built.

но не представляется возможным атомарно разбить метод add_to_tree например, где операция, специфичная для только для потомка, находится внутри цикла
 

findnext

Новичок
что объект класса A должен использоваться в еще одной ситуации для получения другого результата, основываясь на тех же исходных данных + некоторые дополнительные данные.
krafty
а насчёт клонирования объекта не задумывался? Это поможет избежать повторную инициализацию объекта + ты сможешь добавить или изменить то что тебе нужно и получится как бы отдельный объект

-~{}~ 09.04.09 14:18:

атомарно разбить метод add_to_tree
наверное не получится...слишком сложно
 
Сверху