Scheme / Design Pattern para permitir que uma determinada classe externa defina propriedades

5

Eu criei uma solução (em PHP) para um problema e estou imaginando se é um Design Pattern nomeado e se é uma boa prática.

Eu tenho uma classe de coleção e uma classe de item. A classe de coleção é a única permitida para definir os dados protegidos da classe do item, além da própria classe.

Eu fiz isso dando à classe item um método que usa o objeto collection como argumento. O objeto item , em seguida, define seus dados com os objetos collection .

Dessa forma, podemos dizer:

$item_coll = new collection();
$item_coll->load($criterion1, $criterion2);

Como a coleção implementa o IteratorAggregate, também podemos fazer isso:

foreach($item_coll as $item) {
  echo 'Item name is ' . $item->getName();
}

Mesmo depois que uma coleção é carregada, você pode obter uma sub-coleção usando o método getBy($property,$value) :

$sub_collection = $item_coll->getBy('color','green'); // new collection object with green items

E agora eu tenho uma coleção de item objetos com todos os seus dados. Aqui estão as classes (com métodos / propriedades impertinentes não mostrados).

class item {
  protected $id; // id from database table
  protected $prop1; // properties also from database
  protected $prop2;

  public function setData(collection $coll, $id) {
    $data = $coll->getData($id);
    foreach($data as $key=>$value) {
      $this->$key = $value
    }
    return $this;
  }
  public function getId() {
    return $this->id;
  }
}

class collection implements IteratorAggregate { // interface for foreach access to $collection
    protected $data = array();
    protected $collection = array(); // contains 'item' objects
    public function getData($id) {
      if(array_key_exists($id,$this->data) ) {
        return $this->data[$id];
      } else return array();
    }
    public function load(someClass $obj1, someClass2 $obj2) { // arguments not relevant here, they determine the contents of the collection
      // based on arguments, data is loaded from database into $this->data;
      foreach($rows as $row) { // database data
        $this->data[$id] = $row;
        $obj = $this->collection[$id] = new item();
        $obj->setData($this,$id); // collection object passes itself into item object
      }
    }
    public function html() {//
      foreach($this as $obj) {
        // loop through collection to create an html table for display
      }
    }
    public function addItem(item $item) { // add already-existing items to collection
      if(!array_key_exists($id,$this->collection) ) {
        $this->collection[$item->getId()] = $item;
      }
    }
    public function getIterator() { // for IteratorAggregate interface
      return new ArrayIterator($this->collection);
    }
    public function getBy($property,$value) {
      $collection = new static(); // new collection created
      // loop through $this object and fill $collection with matching item objects
      return $collection;
    }
    public function getById($id) { // get a single item object by its id
      if(array_key_exists($id,$this->collection) ) {
        return $this->collection[$id];
      }
    }
}
    
por Buttle Butkus 25.02.2015 / 05:56
fonte

3 respostas

1

Acho que você está tentando usar a injeção de dependência, mas o código não é facilmente legível. Você poderia ter usado três classes em vez de duas:

  1. Coleção: para guardar os itens; na verdade, você poderia usar apenas uma matriz simples
  2. Item
  3. ItemDataManager: para carregar e armazenar em cache os dados do banco de dados de maneira eficiente.

Com essa abordagem, seu código seria:

$idm = new ItemDataManager();
$idm->load(criterion1, criterion2);

E então você poderia passar $ idm como um parâmetro para $ item- > setData. Dessa forma, você obtém uma separação clara de tarefas entre o gerenciamento de coleções e o gerenciamento de dados.

    
por 04.03.2015 / 14:14
fonte
1

O padrão ao qual você está se referindo é chamado de Injeção de dependência

Basicamente, na maioria dos casos, o aplicativo chama a biblioteca / objeto para as informações necessárias, mas em alguns casos, o objeto precisa primeiro ser configurado com o que deve servir o aplicativo. Mas se um objeto genérico assume ou obtém de um local codificado (digamos, arquivo de configuração, etc.), ele não é reutilizável no contexto de outra aplicação. Portanto, o objeto da biblioteca é dependente no Aplicativo para fornecer essas informações. A criação de API em uma biblioteca / objeto onde por Application alimenta a informação é chamada Injeção de Dependência .

Existem três maneiras principais de exercitar a injeção de dependência:

  1. Método construtor: Onde os parâmetros são fornecidos no momento de chamar o construtor.
  2. Método setter: onde o método padrão get / set faz o trabalho.
  3. Método da interface: onde um método dedicado é usado pelo aplicativo para passar as informações.

O método -load() é essencialmente o exemplo do método de interface que é capaz de fornecer vários valores e objetos complexos de uma só vez.

Leia este artigo de Martin Fowler que lhe dará uma ótima perspectiva sobre esse assunto.

    
por 14.07.2015 / 18:48
fonte
0

Isso se parece mais com o Padrão de visitante , embora o controle possa ser revertido. Eu diria que não há padrão aqui, apenas alguns problemas arquitetônicos.

Você tem uma classe collection que carrega dados do banco de dados. Há um padrão de design que descreve esse tipo de comportamento, em que você tem um armazenamento de dados (não necessariamente precisa ser um banco de dados) e um objeto que representa a "coleção" de objetos armazenados: o Padrão de repositório .

Com pouquíssimas exceções, nenhum objeto fora da hierarquia de classes de item deve estar acessando dados protegidos. Em vez disso, você precisa expor os métodos públicos para definir esses dados ou exigir que esses valores sejam passados para o construtor do objeto.

A utilização do Padrão de Repositório, juntamente com o encapsulamento adequado, renderizará sua pergunta original.

    
por 10.03.2016 / 22:32
fonte