Üretilen Fabrikalar
Nette DI, arayüze dayalı olarak otomatik olarak fabrika kodu oluşturabilir, bu da sizi kod yazmaktan kurtarır.
Fabrika, nesneleri oluşturan ve yapılandıran bir sınıftır. Bu nedenle bağımlılıklarını da onlara aktarır. Lütfen fabrikaları kullanmanın belirli bir yolunu tanımlayan ve bu konuyla ilgili olmayan factory method tasarım kalıbı ile karıştırmayın.
Giriş bölümünde böyle bir fabrikanın neye benzediğini göstermiştik:
class ArticleFactory
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
public function create(): Article
{
return new Article($this->db);
}
}
Nette DI otomatik olarak fabrika kodu üretebilir. Tek yapmanız gereken bir arayüz oluşturmaktır ve Nette DI bir uygulama
üretecektir. Arayüz, create
adında tam olarak bir yönteme sahip olmalı ve bir dönüş türü bildirmelidir:
interface ArticleFactory
{
function create(): Article;
}
Dolayısıyla ArticleFactory
fabrikasının Article
nesnelerini oluşturan bir create
yöntemi vardır. Örneğin Article
sınıfı aşağıdaki gibi görünebilir:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
}
Fabrikayı yapılandırma dosyasına ekleyin:
services:
- ArticleFactory
Nette DI ilgili fabrika uygulamasını oluşturacaktır.
Böylece, fabrikayı kullanan kodda, nesneyi arayüze göre talep ederiz ve Nette DI üretilen uygulamayı kullanır:
class UserController
{
public function __construct(
private ArticleFactory $articleFactory,
) {
}
public function foo()
{
// fabrikanın bir nesne oluşturmasına izin verin
$article = $this->articleFactory->create();
}
}
Parametrelendirilmiş Fabrika
create
fabrika yöntemi, daha sonra kurucuya aktaracağı parametreleri kabul edebilir. Örneğin,
Article
sınıfına bir makale yazarı kimliği ekleyelim:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
private int $authorId,
) {
}
}
Ayrıca fabrikaya parametre de ekleyeceğiz:
interface ArticleFactory
{
function create(int $authorId): Article;
}
Yapıcıdaki parametre ve fabrikadaki parametre aynı ada sahip olduğundan, Nette DI bunları otomatik olarak geçirecektir.
Gelişmiş Tanım
Tanım, implement
tuşu kullanılarak çok satırlı olarak da yazılabilir:
services:
articleFactory:
implement: ArticleFactory
Bu uzun şekilde yazarken, normal hizmetlerde olduğu gibi arguments
anahtarındaki kurucu için ek argümanlar ve
setup
kullanarak ek yapılandırma sağlamak mümkündür.
Örnek: create()
yöntemi $authorId
parametresini kabul etmeseydi, yapılandırmada
Article
yapıcısına aktarılacak sabit bir değer belirtebilirdik:
services:
articleFactory:
implement: ArticleFactory
arguments:
authorId: 123
Ya da tersine, eğer create()
parametre kabul etseydi $authorId
ancak bu parametre kurucunun bir
parçası olmasaydı ve Article::setAuthorId()
yöntemi tarafından aktarılsaydı, bu parametreye setup
bölümünde atıfta bulunacaktık:
services:
articleFactory:
implement: ArticleFactory
setup:
- setAuthorId($authorId)
Accessor
Nette, fabrikaların yanı sıra erişimci adı verilen nesneler de üretebilir. Erişimci, DI konteynerinden belirli bir
hizmeti döndüren get()
yöntemine sahip bir nesnedir. Birden fazla get()
çağrısı her zaman aynı
örneği döndürecektir.
Accessor'lar bağımlılıklara tembel yükleme getirir. Hataları özel bir veritabanına kaydeden bir sınıfımız olsun.
Eğer veritabanı bağlantısı sınıfın kurucusunda bir bağımlılık olarak aktarılsaydı, bağlantının her zaman
oluşturulması gerekirdi, ancak sadece nadiren bir hata ortaya çıktığında kullanılacağından bağlantı çoğunlukla
kullanılmadan kalırdı. Bunun yerine, sınıf bir erişimci geçebilir ve get()
yöntemi çağrıldığında,
yalnızca o zaman veritabanı nesnesi oluşturulur:
Bir accessor nasıl oluşturulur? Sadece bir arayüz yazın ve Nette DI uygulamayı oluşturacaktır. Arayüz, get
adında tam olarak bir yönteme sahip olmalı ve dönüş türünü bildirmelidir:
interface PDOAccessor
{
function get(): PDO;
}
Erişiciyi, erişicinin döndüreceği hizmetin tanımıyla birlikte yapılandırma dosyasına ekleyin:
services:
- PDOAccessor
- PDO(%dsn%, %user%, %password%)
Erişimci, PDO
türünde bir hizmet döndürür ve yapılandırmada bu türden yalnızca bir hizmet olduğu için
erişimci bunu döndürür. Bu türde birden fazla yapılandırılmış hizmet varsa, adını kullanarak hangisinin
döndürüleceğini belirtebilirsiniz, örneğin - PDOAccessor(@db1)
.
Multifactory/Accessor
Şimdiye kadar, fabrikalar ve erişimciler yalnızca tek bir nesne oluşturabiliyor veya döndürebiliyordu. Bir erişimci ile
birleştirilmiş bir çoklu fabrika da oluşturulabilir. Böyle bir çoklu fabrika sınıfının arayüzü, aşağıdaki gibi
adlandırılan birden fazla yöntemden oluşabilir create<name>()
ve
get<name>()
Örneğin:
interface MultiFactory
{
function createArticle(): Article;
function getDb(): PDO;
}
Birden fazla oluşturulmuş fabrika ve erişimci geçirmek yerine, yalnızca bir karmaşık çoklu fabrika geçirebilirsiniz.
Alternatif olarak, birden fazla yöntem yerine bir parametre ile get()
adresini kullanabilirsiniz:
interface MultiFactoryAlt
{
function get($name): PDO;
}
Bu durumda, MultiFactory::getArticle()
, MultiFactoryAlt::get('article')
ile aynı şeyi yapar. Ancak,
alternatif sözdiziminin birkaç dezavantajı vardır. Hangi $name
değerlerinin desteklendiği açık değildir ve
birden fazla farklı $name
değeri kullanıldığında dönüş türü arayüzde belirtilemez.
Liste ile Tanımlama
Bu yol, yapılandırmada birden fazla fabrika tanımlamak için kullanılabilir:
services:
- MultiFactory(
article: Article # defines createArticle()
db: PDO(%dsn%, %user%, %password%) # defines getDb()
)
Veya fabrika tanımında, bir referans kullanarak mevcut hizmetlere atıfta bulunabiliriz:
services:
article: Article
- PDO(%dsn%, %user%, %password%)
- MultiFactory(
article: @article # defines createArticle()
db: @\PDO # defines getDb()
)
Etiketlerle Tanım
Bir multifactory'nin nasıl tanımlanacağına dair bir başka seçenek de etiket kullanmaktır:
services:
- App\Core\RouterFactory::createRouter
- App\Model\DatabaseAccessor(
db1: @database.db1.explorer
)