1
0
mirror of https://github.com/php/doc-ja.git synced 2026-03-25 07:32:13 +01:00
Files
archived-doc-ja/reference/objaggregation/examples.xml
2010-03-29 00:47:47 +00:00

454 lines
13 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 96c9d88bad9a7d7d44bfb7f26c226df7ee9ddf26 Maintainer: takagi Status: ready -->
<!-- CREDITS: hirokawa -->
<appendix xml:id="objaggregation.examples">
&reftitle.examples;
<section xml:id="objaggregation.examples.association">
<title>オブジェクトの集約の例</title>
<para>
<emphasis>関連</emphasis>は、独立に構築され、外部から
可視の部分を合成したものです。クラスまたはオブジェクトを
関連づける場合、各クラスは関連するクラスへのリファレンスを保持します。
複数のクラスを静的に関連づける場合は、クラスは他のクラスの
インスタンスへのリファレンスを含みます。例えば、
<example>
<title>クラスの関連付け</title>
<programlisting role="php">
<![CDATA[
<?php
class MyDateTime {
function DateTime()
{
// 空のコンストラクタ
}
function now()
{
return date("Y-m-d H:i:s");
}
}
class Report {
var $_dt;
// その他のプロパティ ...
function Report()
{
$this->_dt = new MyDateTime();
// 初期化コード ...
}
function generateReport()
{
$dateTime = $this->_dt->now();
// その他のコード ...
}
// その他のメソッド ...
}
$rep = new Report();
?>
]]>
</programlisting>
</example>
コンストラクタ (または他のメソッド) にリファレンスを渡すことにより
実行時に複数のインスタンスを関連づけることも可能です。
これにより、複数のオブジェクト間の関連を動的に変更することが
可能です。この例を示すために上の例を変更してみます。
<example>
<title>オブジェクトの関連</title>
<programlisting role="php">
<![CDATA[
<?php
class MyDateTime {
// 上の例と同じ
}
class MyDateTimePlus {
var $_format;
function MyDateTimePlus($format="Y-m-d H:i:s")
{
$this->_format = $format;
}
function now()
{
return date($this->_format);
}
}
class Report {
var $_dt; // MyDateTime へのリファレンスをここに保持
// その他のプロパティ ...
function Report()
{
// 初期化を行う
}
function setMyDateTime(&$dt)
{
$this->_dt =& $dt;
}
function generateReport()
{
$dateTime = $this->_dt->now();
// その他のコード ...
}
// その他のメソッド ...
}
$rep = new Report();
$dt = new MyDateTime();
$dtp = new MyDateTimePlus("l, F j, Y (h:i:s a, T)");
// Web 表示用に簡単な日付を付けたレポートを生成する
$rep->setMyDateTime($dt);
echo $rep->generateReport();
// その他のコード ...
// かっこの良いレポートを生成する
$rep->setMyDateTime($dtp);
$output = $rep->generateReport();
// データベースに $output を保存
// ... 等 ...
?>
]]>
</programlisting>
</example>
</para>
<para>
一方、<emphasis>集約</emphasis>では、合成されたパーツのカプセル化
(隠蔽) が行われます。(静的な) 内部クラス (PHP はまだ内部クラスを
サポートしていません) を使用することにより、クラスを集約することが
できます。この場合、このクラスを含むクラスを通じる場合以外、集約された
クラスの定義にはアクセスできません。複数のインスタンスの集約
(オブジェクト集約) は、あるオブジェクトの内部にサブオブジェクトを
動的に作成することを意味し、この過程でこのオブジェクトのプロパティと
メソッドを拡張します。
</para>
<para>
オブジェクトの集約は、(例えば、分子は原子を集約したものであるといった)
包含関係を表す際の自然な方法であり、サブクラスを複数の親クラス
およびそのインターフェイスに永続的にバインドすることなく、
多重継承と等価な機能を得るために使用できます。
実際、オブジェクトの集約はより柔軟に使用することができ、集約される
オブジェクトで継承するメソッドまたはプロパティを選択することが
できます。
</para>
</section>
<section xml:id="objaggregation.examples2">
&reftitle.examples;
<para>
3 つのクラスを定義し、各々に別々のストレージメソッドを実装します。
</para>
<para>
<example>
<title>storage_classes.inc</title>
<programlisting role="php">
<![CDATA[
<?php
class FileStorage {
var $data;
function FileStorage($data)
{
$this->data = $data;
}
function write($name)
{
$fp = fopen(name, "w");
fwrite($fp, $this->data);
fclose($data);
}
}
class WDDXStorage {
var $data;
var $version = "1.0";
var $_id; // "private" 変数
function WDDXStorage($data)
{
$this->data = $data;
$this->_id = $this->_genID();
}
function store()
{
if ($this->_id) {
$pid = wddx_packet_start($this->_id);
wddx_add_vars($pid, "this->data");
$packet = wddx_packet_end($pid);
} else {
$packet = wddx_serialize_value($this->data);
}
$dbh = dba_open("varstore", "w", "gdbm");
dba_insert(md5(uniqid("", true)), $packet, $dbh);
dba_close($dbh);
}
// プライベートメソッド
function _genID()
{
return md5(uniqid(rand(), true));
}
}
class DBStorage {
var $data;
var $dbtype = "mysql";
function DBStorage($data)
{
$this->data = $data;
}
function save()
{
$dbh = mysql_connect();
mysql_select_db("storage", $dbh);
$serdata = serialize($this->data);
mysql_query("insert into vars ('$serdata',now())", $dbh);
mysql_close($dbh);
}
}
?>
]]>
</programlisting>
</example>
</para>
<para>
この定義済みクラスを用いていくつかのオブジェクトをインスタンス化し、
集約や集約の解除を行いつつ随時オブジェクトの情報を出力します。
</para>
<para>
<example>
<title>test_aggregation.php</title>
<programlisting role="php">
<![CDATA[
<?php
include "storageclasses.inc";
// ユーティリティ関数
function p_arr($arr)
{
foreach ($arr as $k => $v)
$out[] = "\t$k => $v";
return implode("\n", $out);
}
function object_info($obj)
{
$out[] = "クラス: " . get_class($obj);
foreach (get_object_vars($obj) as $var=>$val) {
if (is_array($val)) {
$out[] = "プロパティ: $var (array)\n" . p_arr($val);
} else {
$out[] = "プロパティ: $var = $val";
}
}
foreach (get_class_methods($obj) as $method) {
$out[] = "メソッド: $method";
}
return implode("\n", $out);
}
$data = array(M_PI, "kludge != cruft");
// 基本オブジェクトを作成する
$fs = new FileStorage($data);
$ws = new WDDXStorage($data);
// オブジェクトの情報を表示する
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\n\$ws オブジェクト\n";
echo object_info($ws) . "\n";
// 集約を行う
echo "\n\$fs を WDDXStorage クラスに集約します\n";
aggregate($fs, "WDDXStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\nそれを DBStorage クラスに集約します\n";
aggregate($fs, "DBStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
echo "\nWDDXStorage を集約から解除します\n";
deaggregate($fs, "WDDXStorage");
echo "\$fs オブジェクト\n";
echo object_info($fs) . "\n";
?>
]]>
</programlisting>
</example>
</para>
<para>
出力内容を見ながら、PHP の集約についての副作用や制限事項を
考えてみましょう。
まず、新しく作成されたオブジェクト <varname>$fs</varname> および
<varname>$ws</varname> は、期待通りの (対応するクラス定義に
もとづく) 結果を出力します。
PHP では実際のところクラス/オブジェクトの要素についてパブリック/
プライベートの区別はありませんが、集約の際には
<emphasis>クラス/オブジェクトのプライベート要素はアンダースコア文字
("_") で始まる</emphasis>とみなします。
</para>
<para>
<informalexample>
<programlisting>
<![CDATA[
$fs オブジェクト
クラス: filestorage
プロパティ: data (array)
0 => 3.1415926535898
1 => kludge != cruft
メソッド: filestorage
メソッド: write
$ws オブジェクト
クラス: wddxstorage
プロパティ: data (array)
0 => 3.1415926535898
1 => kludge != cruft
プロパティ: version = 1.0
プロパティ: _id = ID::9bb2b640764d4370eb04808af8b076a5
メソッド: wddxstorage
メソッド: store
メソッド: _genid
]]>
</programlisting>
</informalexample>
</para>
<para>
次に <varname>$fs</varname><classname>WDDXStorage</classname>
クラスと集約し、オブジェクトの情報を出力します。
<varname>$fs</varname> は今でも <classname>FileStorage</classname>
のままですが、プロパティ <varname>$version</varname> およびメソッド
<function>store</function> が存在することがわかるでしょう。これらは
いずれも <classname>WDDXStorage</classname> で定義されているものです。
注意すべき点は、クラスで定義されているプライベート要素は集約されていない
ということです。それらは <varname>$ws</varname> オブジェクトの中には
存在します。また、<classname>WDDXStorage</classname> のコンストラクタも
存在しません。これを集約するのは論理的ではありません。
</para>
<para>
<informalexample>
<programlisting>
<![CDATA[
$fs を WDDXStorage クラスに集約します
$fs オブジェクト
クラス: filestorage
プロパティ: data (array)
0 => 3.1415926535898
1 => kludge != cruft
プロパティ: version = 1.0
メソッド: filestorage
メソッド: write
メソッド: store
]]>
</programlisting>
</informalexample>
</para>
<para>
集約処理は、積み重ねていくことが可能です。そこで今度は
<varname>$fs</varname><classname>DBStorage</classname>
集約します。これにより、定義されているすべてのクラスの
保存処理メソッドを使用可能なオブジェクトができあがります。
</para>
<para>
<informalexample>
<programlisting>
<![CDATA[
それを DBStorage クラスに集約します
$fs オブジェクト
クラス: filestorage
プロパティ: data (array)
0 => 3.1415926535898
1 => kludge != cruft
プロパティ: version = 1.0
プロパティ: dbtype = mysql
メソッド: filestorage
メソッド: write
メソッド: store
メソッド: save
]]>
</programlisting>
</informalexample>
</para>
<para>
最後に、プロパティやメソッドを動的に集約したのと同じ方法で、
集約したプロパティやメソッドを解除することも可能です。
<varname>$fs</varname> から <classname>WDDXStorage</classname>
クラスの集約を解除すると、このような結果になります。
</para>
<para>
<informalexample>
<programlisting>
<![CDATA[
WDDXStorage を集約から解除します
$fs オブジェクト
クラス: filestorage
プロパティ: data (array)
0 => 3.1415926535898
1 => kludge != cruft
プロパティ: dbtype = mysql
メソッド: filestorage
メソッド: write
メソッド: save
]]>
</programlisting>
</informalexample>
</para>
<para>
上で説明しきれなかったことがひとつあります。それは、集約処理の際には
既存のプロパティやメソッドは上書きされないということです。例えば、
<classname>FileStorage</classname> クラスでは
<varname>$data</varname> というプロパティを定義しており、
<classname>WDDXStorage</classname> クラスでも同名のプロパティが
定義されていますが、このプロパティが
<classname>FileStorage</classname> のインスタンス化の際に
取得したプロパティの内容を上書きすることはありません。
</para>
</section>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->