Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Bread::Board::Manual::UsereContributedaPerlard::Manual::Concepts::Advanced(3)

NAME
       Bread::Board::Manual::Concepts::Advanced	- An overview of some of the
       more advanced Bread::Board concepts

VERSION
       version 0.37

INTRODUCTION
       In the Bread::Board::Manual::Concepts document we attempted to explain
       the conceptual foundations of Bread::Board. In that we exposed you to
       the idea	of a container and a service and showed	how they could be
       used. In	that document we built a hierarchical container	which
       organized different sets	of services into what could be seen as
       subsystems within an overall application. While this alone has plenty
       of value, you might be asking yourself, what about re-use?
       Bread::Board already encourages decoupled object	design by removing the
       need to manually	wire your application components together, but what
       about re-using Bread::Board components themselves?

       This document will illustrate some of the more advanced concepts	in
       Bread::Board with the specific focus on re-use and extension.

ADVANCED CONCEPTS
       NOTE: This is just a quick sketch of these docs,	more to	come in	the
       next few	releases, for now I need to get	this one out the door.

   Subclassing
       Bread::Board was	built from the very start to be	an open	system and to
       allow for the subclassing of all	its internal components.

       Here is a simple	example	of extending Bread::Board::Container to	build
       a container specific to your application.

	 package My::Application::Container;
	 use Moose;
	 use Bread::Board;

	 extends 'Bread::Board::Container';

	 has 'log_file_name' =>	(
	     is	     =>	'ro',
	     isa     =>	'Str',
	     default =>	'logfile.log',
	 );

	 sub BUILD {
	     my	$self =	shift;
	     container $self =>	as {

		 service 'log_file' => $self->log_file_name;

		 service 'logger' => (
		     class	  => 'My::FileLogger',
		     lifecycle	  => 'Singleton',
		     dependencies => {
			 log_file => depends_on('log_file'),
		     }
		 );

		 service 'application' => (
		     class	  => 'My::Application',
		     dependencies => {
			 logger	=> depends_on('logger'),
		     }
		 );
	     };
	 }

       Then you	can simply create an instance of the container and instantiate
       an instance of the application.

	 my $c = My::Application::Container->new(
	     name	   => 'MyLoggingContainer',
	     log_file_name => 'other_logfile.log'
	 );

	 my $app = $c->resolve(	service	=> 'application');

       It should be noted that when calling the	constructor of a subclass of
       Bread::Board::Container,	you must pass the "name" attribute as a
       parameter. Additionally you could use the "+name" syntax	in the
       subclass	itself like so:

	 has '+name' =>	( default => 'MyLoggingContainer' );

       which will remove the requirement in the	constructor unless you choose
       to override it.

       It is also possible to extend/specialize	a Bread::Board::Service	type
       to customize it for your	needs.

       More to come later.

   Parameterized Containers
       Extending containers is just one	form of	re-use,	just like extending a
       class in	plain old OOP. But Bread::Board	also provides another means of
       re-use, and that	is parameterized containers.

       If you are familiar with	functors in Standard ML	or O'Caml then this
       might look familiar to you. A parameterized container is	basically a
       container which expects another container (or containers) as an
       argument	and produces a third container as the result.

       Lets take a simple example here of a Logger object which	logs to	a
       database.

	 my $db_logger = container 'DatabaseLogger' => [ 'DBConnInfo' ]	=> as {
	     service 'handle' => (
		 class	      => 'My::Database::Logger',
		 dependencies => {
		     dsn      => depends_on('DBConnInfo/dsn'),
		     username => depends_on('DBConnInfo/username'),
		     password => depends_on('DBConnInfo/password'),
		 }
	     );
	 };

       It is parameterized with	a "DBConnInfo" container which has three
       services, a "dsn", a "username" and a "password".  Now let's create a
       simple container	which fulfills these requirements.

	 my $db_conn_info = container 'DatabaseConnection' => as {
	     service 'dsn'	=> 'dbi:mysql:foo';
	     service 'username'	=> 'bar';
	     service 'password'	=> '***';
	 };

       The above container fulfills the	bare minimum, but this could have just
       as easily have been a much more complex container which also had	a
       service for a DBIx::Class schema, or a KiokuDB directory	object.	As
       long as the container provided the three	required services, that	was
       all that	the "DatabaseLogger" parameterized container required.

       Now, a parameterized container is not a usable container, you must
       create an instance of it. That is as simple as calling the "create"
       method, like so.

	 my $my_db_logger = $db_logger->create(
	     DBConnInfo	=> $db_conn_info
	 );

       After which you can use it just like any	other Bread::Board container
       would be	used.

	 my $log_handle	= $my_db_logger->resolve(
	     service =>	'handle'
	 );

       Parameterized containers	can also be nested, here is an example of an
       Application container that expects a Logger.

	 my $app = container 'Application' => [	'Logger' ] => as {
	     service 'app' => (
		 class	      => 'My::Application',
		 dependencies => {
		     log_handle	=> depends_on('Logger/handle')
		 }
	     );
	 };

       And here	we instantiate an instance of our Application container	using
       the DatabaseLogger.

	 my $db_app = $app->create(
	     Logger => $db_logger->create(
		 DBConnInfo => $db_conn_info
	     )
	 );

       And of course, since the	Logger is a parameter we could just as easily
       pass in a simpler screen	logger for a test environment or something.
       Here is what that would look like.

	 my $simple_logger = container 'SimpleLogger' => as {
	     service 'handle' => (
		 class => 'My::Simple::Logger'
	     );
	 };

	 my $simple_app	= $app->create(
	     Logger => $simple_logger
	 );

       Parameterized containers	provide	a useful and powerful means of re-use
       and abstraction,	making it easy to create flexible containers to	model
       your applications subsystems.

AUTHOR
       Stevan Little <stevan@iinteractive.com>

BUGS
       Please report any bugs or feature requests on the bugtracker website
       https://github.com/stevan/BreadBoard/issues

       When submitting a bug or	request, please	include	a test-file or a patch
       to an existing test-file	that illustrates the bug or desired feature.

COPYRIGHT AND LICENSE
       This software is	copyright (c) 2019, 2017, 2016,	2015, 2014, 2013,
       2011, 2009 by Infinity Interactive.

       This is free software; you can redistribute it and/or modify it under
       the same	terms as the Perl 5 programming	language system	itself.

perl v5.32.0			  2Bread::Board::Manual::Concepts::Advanced(3)

NAME | VERSION | INTRODUCTION | ADVANCED CONCEPTS | AUTHOR | BUGS | COPYRIGHT AND LICENSE

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Bread::Board::Manual::Concepts::Advanced&sektion=3&manpath=FreeBSD+12.2-RELEASE+and+Ports>

home | help