Flyweightパターン
インスタンスを共有し無駄なインスタンスを生成しない
Flyweight とは、英語で「フライ級」を意味する単語です。 フライ級とは、ボクシングなどの体重階級の中で軽い部類に分類できる階級です。もっと軽い階級もありますが。 Flyweight パターンとは、いかにしてプログラムの動作を軽くするかに焦点を当てたパターンです。
Flyweight パターンとは、このように、同じインスタンスを共有することで、無駄なインスタンスを生成しないようにして、 プログラム全体を軽くすることを目的としたパターンなのです。
インスタンスを生成するということは、コンピュータのリソースを使うということです。リソースとはメモリや時間です。インスタンスを生成するときに、一定の時間が掛かるとしてFlyweight パターンを使ってインスタンスを共有すればインスタンスの生成する数を減らしスピードも上げることもできます。
また、Flyweight パターンを利用することで、どのインスタンスを持っているのかなどを、利用者(main クラスのような呼び出し側) で把握しておく必要もなくなります。また、複数の呼び出し先からの要求にも無駄なく応えることが可能となります。
ただし、Flyweight パターンは、ひとつのインスタンスを各所で共有することになりますので、 共有されるインスタンスが本質的(intrinsic)な情報のみを持つ場合にのみ利用するべきです。 非本質的(extrinsic)な情報は、どこかの誰かが変更する可能性のあるものであり、 共有するインスタンスを勝手に誰かが変更することで、そこかしこに影響を与えることになりかねません。
例題
与えられた客先番号から、客先の情報を持つインスタンスを生成するクラスを作りなさい。
25 名前25
1 名前1
共通クラス
|
Flyweightパターンを使用しない例 Main.java public class Main {
public static void main(String[] args) {
Customer c1 = new Customer(1);
System.out.println(c1.getNumber() + " " + c1.getName());
Customer c2 = new Customer(25);
System.out.println(c2.getNumber() + " " + c2.getName());
Customer c3 = new Customer(1);
System.out.println(c3.getNumber() + " " + c3.getName());
}
}
|
Flyweightパターンを使用した例 CustomerFactory.java public class CustomerFactory {
private HashMap<Integer, Customer> pool = new HashMap<Integer, Customer>();
private static CustomerFactory singleton = new CustomerFactory();
private CustomerFactory() {}
public static CustomerFactory getInstance() {
return singleton;
}
public synchronized Customer getCustomer(int number) {
Integer no = new Integer(number);
Customer c = (Customer)pool.get(no);
if (c == null) {
c = new Customer(number);
pool.put(no, c);
}
return c;
}
}
Main.java public class Main {
public static void main(String[] args) {
CustomerFactory factory = CustomerFactory.getInstance();
Customer c1 = factory.getCustomer(1);
System.out.println(c1.getNumber() + " " + c1.getName());
Customer c2 = factory.getCustomer(25);
System.out.println(c2.getNumber() + " " + c2.getName());
Customer c3 = factory.getCustomer(1);
System.out.println(c3.getNumber() + " " + c3.getName());
}
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 main.cpp #include <iostream>
using namespace std;
#include "customer.h"
int main() {
Customer c1(1);
cout << c1.getNumber() << " " << c1.getName() << endl;
Customer c2(25);
cout << c2.getNumber() << " " << c2.getName() << endl;
Customer c3(1);
cout << c3.getNumber() << " " << c3.getName() << endl;
return 0;
}
|
Flyweightパターンを使用した例 customerFactory.h #include <map>
#include <string>
#include "customer.h"
class CustomerFactory
{
private:
std::map<int, Customer*> pool;
public:
CustomerFactory(void);
virtual ~CustomerFactory(void);
Customer* getCustomer(int);
}; customerFactory.cpp #include "customerFactory.h"
using namespace std;
CustomerFactory::CustomerFactory(void) {}
CustomerFactory::~CustomerFactory(void) {
map<int, Customer*>::iterator it = pool.begin();
while(it != pool.end())
delete (it++)->second;
pool.clear();
}
Customer* CustomerFactory::getCustomer(int number) {
map<int, Customer*>::iterator it = pool.find(number);
Customer* c;
if (it != pool.end()) {
c = it->second;
}
else {
c = new Customer(number);
pool.insert(map<int, Customer*>::value_type(number, c));
}
return c;
}
main.cpp #include <iostream>
using namespace std;
#include "customer.h"
#include "customerFactory.h"
int main() {
CustomerFactory* factory = new CustomerFactory();
Customer* c1 = factory->getCustomer(1);
cout << c1->getNumber() << " " << c1->getName() << endl;
Customer* c2 = factory->getCustomer(25);
cout << c2->getNumber() << " " << c2->getName() << endl;
Customer* c3 = factory->getCustomer(1);
cout << c3->getNumber() << " " << c3->getName() << endl;
delete factory;
return 0;
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくいですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、マップ pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 ちなみに、map では、first にキー、second にデータが格納されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Program.cs class Program
{
static void Main(string[] args)
{
Customer c1 = new Customer(1);
Console.WriteLine(c1.GetNumber() + " " + c1.GetName());
Customer c2 = new Customer(25);
Console.WriteLine(c2.GetNumber() + " " + c2.GetName());
Customer c3 = new Customer(1);
Console.WriteLine(c3.GetNumber() + " " + c3.GetName());
}
}
|
Flyweightパターンを使用した例 CustomerFactory.cs class CustomerFactory
{
private Hashtable pool = new Hashtable();
private static CustomerFactory instance =
new CustomerFactory();
public static CustomerFactory GetInstance()
{
return instance;
}
public Customer GetCustomer(int number)
{
Customer c = (Customer)pool[number];
if (c == null)
{
c = new Customer(number);
pool.Add(number, c);
}
return c;
}
} Program.cs class Program
{
static void Main(string[] args)
{
CustomerFactory factory = CustomerFactory.GetInstance();
Customer c1 = factory.GetCustomer(1);
Console.WriteLine(c1.GetNumber() + " " + c1.GetName());
Customer c2 = factory.GetCustomer(25);
Console.WriteLine(c2.GetNumber() + " " + c2.GetName());
Customer c3 = factory.GetCustomer(1);
Console.WriteLine(c3.GetNumber() + " " + c3.GetName());
}
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Program.vb Module Main
Sub Main()
Dim c1 As Customer = New Customer(1)
Console.WriteLine(c1.GetNumber() & " " & c1.GetName())
Dim c2 As Customer = New Customer(25)
Console.WriteLine(c2.GetNumber() & " " & c2.GetName())
Dim c3 As Customer = New Customer(1)
Console.WriteLine(c3.GetNumber() & " " & c3.GetName())
End Sub
End Module
|
Flyweightパターンを使用した例 CustomerFactory.vb Public Class CustomerFactory
Private pool As Hashtable = New Hashtable()
Private Shared instance As CustomerFactory = New CustomerFactory()
Public Shared Function GetInstance() As CustomerFactory
Return instance
End Function
Public Function GetCustomer(ByVal number As Integer) As Customer
Dim c As Customer = pool(number)
If c Is Nothing Then
c = New Customer(number)
pool.Add(number, c)
End If
Return c
End Function
End Class
Program.vb Module Main
Sub Main()
Dim factory As CustomerFactory = CustomerFactory.etInstance()
Dim c1 As Customer = factory.CustomerFactory(1)
Console.WriteLine(c1.GetNumber() & " " & c1.GetName())
Dim c2 As Customer = factory.CustomerFactory(25)
Console.WriteLine(c2.GetNumber() & " " & c2.GetName())
Dim c3 As Customer = factory.CustomerFactory(1)
Console.WriteLine(c3.GetNumber() & " " & c3.GetName())
End Sub
End Module
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.js const Customer = require("./Customer.js");
let c1 = new Customer(1);
process.stdout.write(c1.getNumber() + " " + c1.getName() + "\n");
let c2 = new Customer(25);
process.stdout.write(c2.getNumber() + " " + c2.getName() + "\n");
let c3 = new Customer(1);
process.stdout.write(c3.getNumber() + " " + c3.getName() + "\n");
|
Flyweightパターンを使用した例 CustomerFactory.js const Customer = require("./Customer.js");
module.exports = class CustomerFactory {
static singleton = new CustomerFactory();
constructor() {
this.pool = new Map();
}
static getInstance() {
return CustomerFactory.singleton;
}
getCustomer(number) {
let c = this.pool.get(number);
if (c == null) {
c = new Customer(number);
this.pool.set(number, c);
}
return c;
}
}
Main.js const CustomerFactory = require("./CustomerFactory.js");
let factory = CustomerFactory.getInstance();
let c1 = factory.getCustomer(1);
process.stdout.write(c1.getNumber() + " " + c1.getName() + "\n");
let c2 = factory.getCustomer(25);
process.stdout.write(c2.getNumber() + " " + c2.getName() + "\n");
let c3 = factory.getCustomer(1);
process.stdout.write(c3.getNumber() + " " + c3.getName() + "\n");
}
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.pl use lib qw(./);
use Customer;
my $c1 = new Customer(1);
print $c1->getNumber() . " " . $c1->getName() . "\n";
my $c2 = new Customer(25);
print $c2->getNumber() . " " . $c2->getName() . "\n";
my $c3 = new Customer(1);
print $c3->getNumber() . " " . $c3->getName() . "\n";
|
Flyweightパターンを使用した例 CustomerFactory.pm use Customer;
package CustomerFactory {
use feature 'state';
static $singleton = new CustomerFactory();
sub new {
my ($class) = @_;
my $this = { pool => {} };
return bless $this, $class;
}
sub getInstance {
return $singleton;
}
sub getCustomer {
my ($this, $number) = @_;
my $c = $this->{pool}->{$number};
if ($c == undef) {
$c = new Customer($number);
$this->{pool}{$number} = $c;
}
return $c;
}
}
1;
Main.pl use lib qw(./);
use CustomerFactory;
my $factory = CustomerFactory::getInstance();
my $c1 = $factory->getCustomer(1);
print $c1->getNumber() . " " . $c1->getName() . "\n";
my $c2 = $factory->getCustomer(25);
print $c2->getNumber() . " " . $c2->getName() . "\n";
my $c3 = $factory->getCustomer(1);
print $c3->getNumber() . " " . $c3->getName() . "\n";
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.rb require './Customer'
c1 = Customer.new(1)
puts "#{c1.getNumber()} #{c1.getName()}"
c2 = Customer.new(25)
puts "#{c2.getNumber()} #{c2.getName()}"
c3 = Customer.new(1)
puts "#{c3.getNumber()} #{c3.getName()}"
|
Flyweightパターンを使用した例 CustomerFactory.rb require './Customer'
class CustomerFactory
@@singleton = CustomerFactory.new()
@@pool = {}
def self.getInstance()
return @@singleton
end
def getCustomer(number)
c = @@pool[number]
if c.nil? then
c = Customer.new(number)
@@pool[number] = c
end
return c
end
end
Main.rb require './CustomerFactory'
factory = CustomerFactory.getInstance()
c1 = factory.getCustomer(1)
puts "#{c1.getNumber()} #{c1.getName()}"
c2 = factory.getCustomer(25)
puts "#{c2.getNumber()} #{c2.getName()}"
c3 = factory.getCustomer(1)
puts "#{c3.getNumber()} #{c3.getName()}"
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.java from Customer import Customer
c1 = new Customer(1)
print(f"{c1.getNumber()} {c1.getName()}")
c2 = new Customer(25)
print(f"{c2.getNumber()} {c2.getName()}")
c3 = new Customer(1)
print(f"{c3.getNumber()} {c3.getName()}")
|
Flyweightパターンを使用した例 CustomerFactory.py from Customer import Customer
class CustomerFactory:
__instance = None
def __init__(self):
self.pool = {}
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = cls()
return cls.__instance
def getCustomer(self, number):
if self.pool.get(number):
c = self.pool[number]
else:
c = Customer(number)
self.pool[number] = c
return c
Main.py from CustomerFactory import CustomerFactory
factory = CustomerFactory.getInstance()
c1 = factory.getCustomer(1)
print(f"{c1.getNumber()} {c1.getName()}")
c2 = factory.getCustomer(25)
print(f"{c2.getNumber()} {c2.getName()}")
c3 = factory.getCustomer(1)
print(f"{c3.getNumber()} {c3.getName()}")
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.php <?php
require_once('Customer.php');
$c1 = new Customer(1);
print $c1->getNumber() . " " . $c1->getName() . "\n";
$c2 = new Customer(25);
print $c2->getNumber() . " " . $c2->getName() . "\n";
$c3 = new Customer(1);
print $c3->getNumber() . " " . $c3->getName() . "\n";
?>
|
Flyweightパターンを使用した例 CustomerFactory.php <?php
require_once('Customer.php');
class CustomerFactory {
private $pool;
private static $singleton;
private function __construct() {
$this->pool = array();
}
public static function getInstance() {
if (!isset(self::$singleton)) {
self::$singleton = new CustomerFactory();
}
return self::$singleton;
}
public function getCustomer($number) {
if (array_key_exists($number, $this->pool) == null) {
$c = new Customer($number);
$this->pool[$number] = $c;
}
else {
$c = $this->pool[$number];
}
return $c;
}
}
?>
Main.php <?php
require_once('Customer.php');
$factory = CustomerFactory::getInstance();
$c1 = $factory->getCustomer(1);
print $c1->getNumber() . " " . $c1->getName() . "\n";
$c2 = $factory->getCustomer(25);
print $c2->getNumber() . " " . $c2->getName() . "\n";
$c3 = $factory->getCustomer(1);
print $c3->getNumber() . " " . $c3->getName() . "\n";
?>
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、$c1 と $c3 は同じ情報なので、新たに $c3 を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、配列 $pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.ts import {Customer} from "./Customer";
let c1:Customer = new Customer(1);
process.stdout.write(c1.getNumber() + " " + c1.getName());
let c2:Customer = new Customer(25);
process.stdout.write(c2.getNumber() + " " + c2.getName());
let c3:Customer = new Customer(1);
process.stdout.write(c3.getNumber() + " " + c3.getName());
|
Flyweightパターンを使用した例 CustomerFactory.ts import {Customer} from "./Customer";
export
class CustomerFactory {
private static singleton:CustomerFactory = new CustomerFactory();
private pool:Map<number, Customer> = new Map<number, Customer>();
public static getInstance():CustomerFactory {
return CustomerFactory.singleton;
}
public getCustomer(number:number):Customer {
let c:Customer = this.pool.get(number);
if (c == null) {
c = new Customer(number);
this.pool.set(number, c);
}
return c;
}
}
Main.ts import {CustomerFactory} from "./CustomerFactory";
import {Customer} from "./Customer";
let factory:CustomerFactory = CustomerFactory.getInstance();
let c1:Customer = factory.getCustomer(1);
process.stdout.write(c1.getNumber() + " " + c1.getName() + "\n");
let c2:Customer = factory.getCustomer(25);
process.stdout.write(c2.getNumber() + " " + c2.getName() + "\n");
let c3:Customer = factory.getCustomer(1);
process.stdout.write(c3.getNumber() + " " + c3.getName() + "\n");
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.swift let c1:Customer = Customer(1)
print(String(c1.getNumber()) + " " + c1.getName())
let c2:Customer = Customer(25)
print(String(c2.getNumber()) + " " + c2.getName())
let c3:Customer = Customer(1)
print(String(c3.getNumber()) + " " + c3.getName())
|
Flyweightパターンを使用した例 CustomerFactory.swift public class CustomerFactory {
private var pool:[Int:Customer] = [:]
private static let singleton:CustomerFactory = CustomerFactory()
public static func getInstance() -> CustomerFactory {
return singleton
}
public func getCustomer(_ number:Int) -> Customer {
var c:Customer! = pool[number]
if c == nil {
c = Customer(number)
pool[number] = c
}
return c
}
}
Main.swift let factory:CustomerFactory = CustomerFactory.getInstance()
let c1:Customer = factory.getCustomer(1)
print(String(c1.getNumber()) + " " + c1.getName())
let c2:Customer = factory.getCustomer(25)
print(String(c2.getNumber()) + " " + c2.getName())
let c3:Customer = factory.getCustomer(1)
print(String(c3.getNumber()) + " " + c3.getName())
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.kt fun main() {
val c1 = Customer(1)
println("${c1.number} ${c1.name}")
val c2 = Customer(25)
println("${c2.number} ${c2.name}")
val c3 = Customer(1)
println("${c3.number} ${c3.name}")
}
|
Flyweightパターンを使用した例 CustomerFactory.kt class CustomerFactory {
private val pool = HashMap<Int, Customer>()
companion object {
private val instance = CustomerFactory()
fun getInstance(): CustomerFactory {
return instance
}
}
@Synchronized
fun getCustomer(number: Int): Customer {
var c = pool[number]
if (c == null) {
c = Customer(number)
pool[number] = c
}
return c
}
}
Main.kt fun main() {
var factory:CustomerFactory = CustomerFactory.getInstance()
var c1:Customer = factory.getCustomer(1)
println("${c1.number} ${c1.name}")
var c2:Customer = factory.getCustomer(25)
println("${c2.number} ${c2.name}")
var c3:Customer = factory.getCustomer(1)
println("${c3.number} ${c3.name}")
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.scala object Main {
def main(args: Array[String]) {
val c1 = new Customer(1)
System.out.println(c1.number + " " + c1.name)
val c2 = new Customer(25)
System.out.println(c2.number + " " + c2.name)
val c3 = new Customer(1)
System.out.println(c3.number + " " + c3.name)
}
}
|
Flyweightパターンを使用した例 CustomerFactory.scala import scala.collection.mutable.HashMap
object CustomerFactory {
private val instance = new CustomerFactory()
def getInstance(): CustomerFactory = instance
}
class CustomerFactory {
private val pool = HashMap[Int, Customer]()
def getCustomer(number: Int): Customer {
var c: Customer = null
try {
c = pool.apply(number)
}
catch {
case _: NoSuchElementException =>
c = new Customer(number)
pool.put(number, c)
}
c
}
}
Main.scala object Main {
def main(args: Array[String]) {
val factory = CustomerFactory.getInstance()
var c1 = factory.getCustomer(1)
System.out.println(c1.number + " " + c1.name)
var c2 = factory.getCustomer(25)
System.out.println(c2.number + " " + c2.name)
var c3 = factory.getCustomer(1)
System.out.println(c3.number + " " + c3.name)
}
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.groovy class Main {
static void main(String[] args) {
Customer c1 = new Customer(1)
System.out.println(c1.number + " " + c1.name)
Customer c2 = new Customer(25)
System.out.println(c2.number + " " + c2.name)
Customer c3 = new Customer(1)
System.out.println(c3.number + " " + c3.name)
}
}
|
Flyweightパターンを使用した例 CustomerFactory.groovy class CustomerFactory {
private HashMap<Integer, Customer> pool = new HashMap<Integer, Customer>()
private static CustomerFactory singleton = new CustomerFactory()
private CustomerFactory() {}
static CustomerFactory getInstance() {
return singleton
}
synchronized Customer getCustomer(int number) {
Integer no = new Integer(number)
Customer c = (Customer)pool.get(no)
if (c == null) {
c = new Customer(number)
pool.put(no, c)
}
return c
}
}
Main.groovy public class Main {
public static void main(String[] args) {
CustomerFactory factory = CustomerFactory.getInstance()
Customer c1 = factory.getCustomer(1)
System.out.println(c1.number + " " + c1.name)
Customer c2 = factory.getCustomer(25)
System.out.println(c2.number + " " + c2.name)
Customer c3 = factory.getCustomer(1)
System.out.println(c3.number + " " + c3.name)
}
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.groovy import "fmt"
func main() {
var c1 = NewCustomer(1)
fmt.Printf("%d %s\n", c1.Number, c1.Name)
var c2 = NewCustomer(25)
fmt.Printf("%d %s\n", c2.Number, c2.Name)
var c3 = NewCustomer(1)
fmt.Printf("%d %s\n", c3.Number, c3.Name)
}
|
Flyweightパターンを使用した例 CustomerFactory.go type CustomerFactory struct {
pool = map[int]*Customer
}
var singleton = &CustomerFactory{}
func GetInstance() *CustomerFactory {
return singleton
}
func (self *CustomerFactory) GetCustomer(number int) *Customer {
var c, ok = self.pool[number]
if ok == false {
if self.pool == nil {
self.pool = map[int]*Customer{}
}
c = NewCustomer(number)
self.pool[number] = c
}
return c
}
Main.go import "fmt"
func main() {
var factory = GetInstance()
var c1 = factory.GetCustomer(1)
fmt.Printf("%d %s\n", c1.Number, c1.Name)
var c2 = factory.GetCustomer(25)
fmt.Printf("%d %s\n", c2.Number, c2.Name)
var c3 = factory.GetCustomer(1)
fmt.Printf("%d %s\n", c3.Number, c3.Name)
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 main.d import customer;
int main() {
Customer c1 = new Customer(1);
printfln("%d %s", c1.getNumber(), c1.getName());
Customer c2 = new Customer(25);
printfln("%d %s", c2.getNumber(), c2.getName());
Customer c3 = new Customer(1);
printfln("%d %s", c3.getNumber(), c3.getName());
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
Flyweightパターンを使用した例 customerfactory.d import customer;
public class CustomerFactory {
private Customer[int] pool;
private static CustomerFactory singleton;
private static this() {
singleton = new CustomerFactory();
}
public static CustomerFactory getInstance() {
return singleton;
}
public Customer getCustomer(in int number) {
Customer c;
if (number in pool) {
c = pool[number];
}
else {
c = new Customer(number);
synchronized {
pool[number] = c;
}
}
return c;
}
}
main.d import customerfactory;
import customer;
int main() {
CustomerFactory factory = CustomerFactory.getInstance();
Customer c1 = factory.getCustomer(1);
printfln("%d %s", c1.getNumber(), c1.getName());
Customer c2 = factory.getCustomer(25);
printfln("%d %s", c2.getNumber(), c2.getName());
Customer c3 = factory.getCustomer(1);
printfln("%d %s", c3.getNumber(), c3.getName());
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |
共通クラス
|
Flyweightパターンを使用しない例 Main.dpr program Main;
uses
System.SysUtils,
UnitCustomer;
var
c1, c2, c3:Customer;
begin
c1 := Customer.Create(1);
Writeln(Format('%d %s', [c1.getNumber(), c1.getName()]));
c2 := Customer.Create(25);
Writeln(Format('%d %s', [c2.getNumber(), c2.getName()]));
c3 := Customer.Create(1);
Writeln(Format('%d %s', [c3.getNumber(), c3.getName()]));
c1.Free;
c2.Free;
c3.Free;
end.
|
Flyweightパターンを使用した例 CustomerFactory.pas unit UnitCustomerFactory;
interface
uses
System.Generics.Collections,
UnitCustomer;
type
CustomerFactory = class
private
var pool:TDictionary<integer, Customer>;
class var singleton:CustomerFactory;
public
class constructor Create();
constructor Create();
class function getInstance():CustomerFactory;
function getCustomer(number:integer):Customer;
end;
implementation
class constructor CustomerFactory.Create();
begin
singleton := CustomerFactory.Create();
end;
constructor CustomerFactory.Create();
begin
pool := TDictionary<integer, Customer>.Create();
end;
class function CustomerFactory.getInstance():CustomerFactory;
begin
Result := singleton;
end;
function CustomerFactory.getCustomer(number:integer):Customer;
var c:Customer;
begin
if pool.ContainsKey(number) = false then begin
c := Customer.Create(number);
pool.Add(number, c);
end
else begin
c := pool.Items[number];
end;
Result := c;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitCustomer,
UnitCustomerFactory;
var
c1, c2, c3:Customer;
factory:CustomerFactory;
begin
factory := CustomerFactory.getInstance();
c1 := factory.getCustomer(1);
Writeln(Format('%d %s', [c1.getNumber(), c1.getName()]));
c2 := factory.getCustomer(25);
Writeln(Format('%d %s', [c2.getNumber(), c2.getName()]));
c3 := factory.getCustomer(1);
Writeln(Format('%d %s', [c3.getNumber(), c3.getName()]));
c1.Free;
c2.Free;
c3.Free;
factory.Free;
end.
|
|
この例では、与えられた客先番号をもとにデータベースから、その客先の情報を取り出すクラス Customer を作成しています。このクラスを利用する側は、客先番号を引数に、この Customer クラスのインスタンスを生成すれば、後は、そのメソッドを呼び出すだけで必要な情報が得られます。 この例では1、25、そしてまた1の客先番号の情報を得ています。しかし、同じ1の客先の情報を得るのに、別のインスタンスを生成していて、無駄があります。つまり、c1 と c3 は同じ情報なので、新たに c3 に設定する情報を生成する必要は無いのです。 この例のように、生成する数が少ないとか、生成する場所が限定されているのならば、まだ分かります。しかし、そうでなければ、すでに必要なインスタンスが生成されているかどうかは分かりにくですし、生成されているのは分かっていても、参照できないようになっているかもしれません。 (スーパクラスや他のサブクラスで private な変数に入れられている、など) |
Flyweight パターンでは、一度生成された、客先番号のインスタンスは、 (この例では、ハッシュテーブル pool に)保存されています。よって、同じ客先番号であれば、この保存されたインスタンスが返されます。まだ生成されていない、初めての客先番号の場合は、インスタンスが生成され、そのインスタンスが返されると同時に保存されます。 |