← 一覧に戻る
構造に関するパターン

Flyweight

同じものを共有して無駄をなくす

概要

  • 等価なオブジェクトは共有したら軽量化できるよねって話

マンガでわかる Flyweight

マンガでわかる Flyweight #デザインパターン - Qiita

でざぱたんで覚える Flyweight

ちびキャラは「フライウェイトたん」。謁見の間に一日中常駐する姫(シングルトンたんの妹)で、口癖は「いちから説明するのはいやですわ」。毎回いちから生成せず、常駐している一人にみんなが会いに行く=キャッシュしたインスタンスの使い回しがFlyweight。本書の整理では「Singletonの緩いヤツ」で、Singletonを検討するときは一緒に検討せよ、とのこと。

出典: いしだけ『でざぱたん: ちびキャラで覚えるデザインパターン』(P.150〜)

登場人物

  • ファクトリ: 生成するやつ
  • フライウェイト: 軽くしたいやつ

やり方

  1. ファクトリはフライウェイトオブジェクトをメンバーに持つ
  2. ファクトリ自身はpublicでstaticな、1度目の呼び出しだけ「生成」し2度目以降の呼び出しはすでに生成したやつを返すgetInstanceメソッドを持つ
  3. ファクトリからのフライウェイトは、既にあれば既存のものを返し、なかったら一度だけ生成して登録して返す

クラス図

pattern

このサイトの実装(big numberの例)での対応関係:

classDiagram
  class BigChar {
    -charname char
    -fontdata String
    +print()
  }
  class BigCharFactory {
    -pool HashMap
    +getInstance() BigCharFactory
    +getBigChar(charname) BigChar
  }
  class BigString {
    -bigchars BigChar[]
    +print()
  }
  BigCharFactory o-- BigChar
  BigString o-- BigChar
  BigString ..> BigCharFactory

メリット

  • メモリ節約:これに尽きる
  • 時間節約:インスタンス生成に時間のかかるオブジェクトなら

注意点

intrinsic(本来備わっている情報)かextrinsic(外からやってきた情報)か

Flyweightに変更を加えると当然だけどアプリケーション内のFlyweightインスタンス全てに変更が共有される。

  • イントリンジック: 場所や状況に依存しない情報。共有して良いのでFlyweightに組み込んで良い
  • エクストリンジック: 場所や状況に応じ変わる情報。共有されるとおかしいので、組み込んではいけない
Java

big number text たち

big0.txt
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
big1.txt
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
big2.txt
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
big3.txt
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
big4.txt
........##......
......####......
....##..##......
..##....##......
..##########....
........##......
......######....
................
big5.txt
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
big6.txt
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
big7.txt
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
big9.txt
....######......
..##......##....
..##......##....
....########....
..........##....
..##......##....
....######......
................
big8.txt
....######......
..##......##....
..##......##....
....######......
..##......##....
..##......##....
....######......
................
big-.txt
................
................
................
................
..##########....
................
................
................
BigString.java
public class BigString {
    // 「大きな文字」の配列
    private BigChar[] bigchars;
    // コンストラクタ
    public BigString(String string) {
        bigchars = new BigChar[string.length()];
        BigCharFactory factory = BigCharFactory.getInstance();
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i] = factory.getBigChar(string.charAt(i));
        }
    }
    // 表示
    public void print() {
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i].print();
        }
    }
}
BigCharFactory.java
import java.util.HashMap;

public class BigCharFactory {
    // すでに作ったBigCharのインスタンスを管理
    private HashMap pool = new HashMap();
    // Singletonパターン
    private static BigCharFactory singleton = new BigCharFactory();
    // コンストラクタ
    private BigCharFactory() {
    }
    // 唯一のインスタンスを得る
    public static BigCharFactory getInstance() {
        return singleton;
    }
    // BigCharのインスタンス生成(共有)
    public synchronized BigChar getBigChar(char charname) {
        BigChar bc = (BigChar)pool.get("" + charname);
        if (bc == null) {
            bc = new BigChar(charname); // ここでBigCharのインスタンスを生成
            pool.put("" + charname, bc);
        }
        return bc;
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java Main digits");
            System.out.println("Example: java Main 1212123");
            System.exit(0);
        }
        BigString bs = new BigString(args[0]);
        bs.print();
    }
}
BigChar.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BigChar {
    // 文字の名前
    private char charname;
    // 大きな文字を表現する文字列('#' '.' '\n'の列)
    private String fontdata;
    // コンストラクタ
    public BigChar(char charname) {
        this.charname = charname;
        try {
            BufferedReader reader = new BufferedReader(
                new FileReader("big" + charname + ".txt")
            );
            String line;
            StringBuffer buf = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buf.append(line);
                buf.append("\n");
            }
            reader.close();
            this.fontdata = buf.toString();
        } catch (IOException e) {
            this.fontdata = charname + "?";
        }
    }
    // 大きな文字を表示する
    public void print() {
        System.out.print(fontdata);
    }
}
Go

BigCharFactorysync.OnceによるSingletonで、生成済みのBigCharpoolにキャッシュする。ログで「生成」と「共有」を区別して表示し、Flyweightの本質(同じ文字は使い回す)が見えるようにしている。

実行: go run ./GoF/patterns/Flyweight/go 1212123

$ go run ./GoF/patterns/Flyweight/go 1212123
big_char.go
package main

import (
	"os"
	"strings"
)

// BigChar は Flyweight そのもの。1文字ぶんの「大きな文字」を表す。
// charname(intrinsic state) が同じなら fontdata の中身も必ず同じになるため、
// BigCharFactory が使い回しても問題が起きない(=共有安全)。
type BigChar struct {
	charname byte   // 文字の名前
	fontdata string // 大きな文字を表現する文字列('#' '.' '\n'の列)
}

// newBigChar はコンストラクタ相当。fontDir 配下の "big<charname>.txt" を読む。
// Java版はファイルを直接カレントディレクトリから読むが、
// Go版はどこから実行しても動くよう、呼び出し元(BigCharFactory)からfontDirを渡してもらう。
func newBigChar(charname byte, fontDir string) *BigChar {
	path := fontDir + string(os.PathSeparator) + "big" + string(charname) + ".txt"
	data, err := os.ReadFile(path)
	fontdata := string(charname) + "?"
	if err == nil {
		// Java版はBufferedReaderで1行ずつ読んで"\n"を足し直すが、
		// テキストファイルなのでそのまま文字列化すれば同じ結果になる。
		fontdata = strings.ReplaceAll(string(data), "\r\n", "\n")
	}
	return &BigChar{charname: charname, fontdata: fontdata}
}

// Print は大きな文字を標準出力へ書き出す。
func (b *BigChar) Print() {
	os.Stdout.WriteString(b.fontdata)
}
big_char_factory.go
package main

import (
	"fmt"
	"path/filepath"
	"runtime"
	"sync"
)

// BigCharFactory は Flyweight を生成・共有する工場(FlyweightFactory)。
// 同じ charname を渡された場合は新規生成せず、poolに貯めた既存インスタンスを返す。
// ここが Flyweight パターンの本質=「同じものは1つだけ作って使い回す」。
type BigCharFactory struct {
	mu   sync.Mutex
	pool map[byte]*BigChar
}

// bigCharFactorySingleton と bigCharFactoryOnce で Singleton化する。
// Java版は静的フィールド+privateコンストラクタだが、Goには対応物がないので
// sync.Once で「最初の呼び出し時に1回だけ生成」を保証する。
var (
	bigCharFactorySingleton *BigCharFactory
	bigCharFactoryOnce      sync.Once
)

// getBigCharFactory は唯一のインスタンスを返す(Java版のgetInstance()相当)。
func getBigCharFactory() *BigCharFactory {
	bigCharFactoryOnce.Do(func() {
		bigCharFactorySingleton = &BigCharFactory{pool: make(map[byte]*BigChar)}
	})
	return bigCharFactorySingleton
}

// GetBigChar はcharname1文字ぶんのBigCharを返す(生成 or 共有)。
// Java版のsynchronizedメソッドに倣い、mutexでpoolへのアクセスを直列化する。
func (f *BigCharFactory) GetBigChar(charname byte) *BigChar {
	f.mu.Lock()
	defer f.mu.Unlock()

	if bc, ok := f.pool[charname]; ok {
		fmt.Printf("[BigCharFactory] 共有: '%c' は既存のインスタンス(%p)を再利用します (pool size=%d)\n", charname, bc, len(f.pool))
		return bc
	}

	bc := newBigChar(charname, fontDir()) // ここでBigCharのインスタンスを生成
	f.pool[charname] = bc
	fmt.Printf("[BigCharFactory] 生成: '%c' の新しいインスタンス(%p)を作成しました (pool size=%d)\n", charname, bc, len(f.pool))
	return bc
}

// fontDir はこのソースファイル自身が置かれているディレクトリを返す。
// `go run ./GoF/patterns/Flyweight/go` のようにリポジトリルートから実行しても、
// big<N>.txt をカレントディレクトリ非依存で見つけられるようにするため、
// runtime.Caller(0) でコンパイル時のソースパスを取得して解決する。
func fontDir() string {
	_, file, _, _ := runtime.Caller(0)
	return filepath.Dir(file)
}
big_string.go
package main

// BigString は「大きな文字」の並び。BigCharという小さなFlyweightの集合として
// 1つの大きな文字列を表す(GoFのいうComposite的な使い方)。
type BigString struct {
	bigchars []*BigChar
}

// newBigString はコンストラクタ相当。1文字ずつFactoryにBigCharを問い合わせる。
// 同じ数字が複数回登場しても、ここで生成されるのは種類の数だけ
// (残りはFactoryが共有インスタンスを返す)。
func newBigString(s string) *BigString {
	bs := &BigString{bigchars: make([]*BigChar, len(s))}
	factory := getBigCharFactory()
	for i := 0; i < len(s); i++ {
		bs.bigchars[i] = factory.GetBigChar(s[i])
	}
	return bs
}

// Print は保持している各BigCharを順に表示する。
func (bs *BigString) Print() {
	for _, bc := range bs.bigchars {
		bc.Print()
	}
}
main.go
package main

import (
	"fmt"
	"os"
)

// 実行:
//
//	go run ./GoF/patterns/Flyweight/go 1212123
//
// Java版と同じお題: 引数の数字文字列を1文字ずつ「大きな文字」に変換して表示する。
// BigCharFactoryが同じ文字のBigCharインスタンスをキャッシュ・共有するので、
// 例えば "1212123" のように同じ数字(1, 2)が複数回出てくると、
// 2回目以降は新規生成せず使い回したことが標準出力のログでわかる。
func main() {
	if len(os.Args) != 2 {
		fmt.Println("Usage: go run ./GoF/patterns/Flyweight/go digits")
		fmt.Println("Example: go run ./GoF/patterns/Flyweight/go 1212123")
		os.Exit(0)
	}
	bs := newBigString(os.Args[1])
	fmt.Println()
	bs.Print()
}
big0.txt
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
big1.txt
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
big2.txt
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
big3.txt
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
big4.txt
........##......
......####......
....##..##......
..##....##......
..##########....
........##......
......######....
................
big5.txt
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
big6.txt
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
big7.txt
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
big8.txt
....######......
..##......##....
..##......##....
....######......
..##......##....
..##......##....
....######......
................
big9.txt
....######......
..##......##....
..##......##....
....########....
..........##....
..##......##....
....######......
................
big-.txt
................
................
................
................
..##########....
................
................
................
PHP
index.php
<?php


/**
 * キャッシュを作ってインスタンス生成の負荷を減らす
 * 要するにゆるいシングルトン
 * むしろこいつのきつい版がシングルトン
 * もしシングルトンを検討するときは、
 * まず先にこいつを検討して
 */


/**
 * シングルトンは自分が唯一複製されない
 * フライウェイトは他のクラスを複製しない
 * シングルトン的なやつに引数を渡して状況に応じて
 * キャッシュからインスタンスを返したり
 * キャッシュしながらインスタンスを返したりする
 */


/**
 * 腹心
 */

class Confidant
{
  private $name;

  public function __construct($key)
  {
    $this->name = $key;
  }
}


/**
 * 腹心を雇い、
 * 一度作ったものは共有されるファクトリー
 * シングルトンで実装
 */


class ConfidantFactory
{
  private $confidant = array();
  private static $instance = null;

  private function __construct()
  {
  }

  public static function getInstance()
  {
    if (!self::$instance) {
      self::$instance = new ConfidantFactory();
    }
    return self::$instance;
  }

  /**
   * 初めて雇うものは
   * 生成され、すでに雇っているものは作ったものが共有される
   */

  public function get($key)
  {
    if (!$this->confidant[$key]) {
      $this->confidant[$key] = new Confidant($key);
      print "[$key]を新たに雇うのです。<br>";
    } else {
      print "すでにいるので使いまわしましょう。<br>";
    }
    return $this->confidant[$key];
  }
}

$factory = ConfidantFactory::getInstance();
if ($factory->get("執事") === $factory->getInstance()->get("執事")) {
  print  "同じオブジェクトなのです";
  # code...
} else {
  print "別オブジェクトです";
}
TypeScript

Go版と同じ「生成/共有」ログを出すキャッシュ実装。

実行: npx tsx GoF/patterns/Flyweight/typescript/main.ts 1212123

$ npx tsx GoF/patterns/Flyweight/typescript/main.ts 1212123
big_char.ts
import { readFileSync } from "node:fs";
import { join } from "node:path";

// BigChar: Flyweightそのもの。1文字ぶんの「大きな文字」を表す。
// charname(intrinsic state)が同じならfontdataの中身も必ず同じになるため、
// BigCharFactoryが使い回しても問題が起きない(=共有安全)。
export class BigChar {
  private readonly charname: string;
  private readonly fontdata: string;

  // コンストラクタ。fontDir配下の"big<charname>.txt"を読む。
  // Java版はカレントディレクトリから直接読むが、TS版はどこから実行しても
  // 動くよう、呼び出し元(BigCharFactory)からfontDirを渡してもらう。
  constructor(charname: string, fontDir: string) {
    this.charname = charname;
    try {
      const raw = readFileSync(join(fontDir, `big${charname}.txt`), "utf-8");
      this.fontdata = raw.replace(/\r\n/g, "\n");
    } catch {
      this.fontdata = `${charname}?`;
    }
  }

  // 大きな文字を表示する
  print(): void {
    process.stdout.write(this.fontdata);
  }
}
big_char_factory.ts
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { BigChar } from "./big_char";

// このソースファイル自身が置かれているディレクトリ。
// `npx tsx GoF/patterns/Flyweight/typescript/main.ts 1212123` のように
// リポジトリルートから実行しても、big<N>.txtをカレントディレクトリ非依存で
// 見つけられるようにするため、import.meta.urlから解決する(Go版のruntime.Caller相当)。
const FONT_DIR = dirname(fileURLToPath(import.meta.url));

// BigCharFactory: Flyweightを生成・共有する工場(FlyweightFactory)。
// 同じcharnameを渡された場合は新規生成せず、poolに貯めた既存インスタンスを返す。
// ここがFlyweightパターンの本質=「同じものは1つだけ作って使い回す」。
export class BigCharFactory {
  private static singleton: BigCharFactory | undefined;

  private readonly pool = new Map<string, BigChar>();

  // privateコンストラクタでSingleton化(Java版と同じ意図。
  // TSクラスは`private constructor`をそのまま書ける)。
  private constructor() {}

  // getInstance: 唯一のインスタンスを得る。
  static getInstance(): BigCharFactory {
    if (!BigCharFactory.singleton) {
      BigCharFactory.singleton = new BigCharFactory();
    }
    return BigCharFactory.singleton;
  }

  // getBigChar: charname1文字ぶんのBigCharを返す(生成 or 共有)。
  getBigChar(charname: string): BigChar {
    const cached = this.pool.get(charname);
    if (cached) {
      console.log(
        `[BigCharFactory] 共有: '${charname}' は既存のインスタンスを再利用します (pool size=${this.pool.size})`,
      );
      return cached;
    }

    const bc = new BigChar(charname, FONT_DIR); // ここでBigCharのインスタンスを生成
    this.pool.set(charname, bc);
    console.log(
      `[BigCharFactory] 生成: '${charname}' の新しいインスタンスを作成しました (pool size=${this.pool.size})`,
    );
    return bc;
  }
}
big_string.ts
import { BigChar } from "./big_char";
import { BigCharFactory } from "./big_char_factory";

// BigString: 「大きな文字」の並び。BigCharという小さなFlyweightの集合として
// 1つの大きな文字列を表す。
export class BigString {
  private readonly bigchars: BigChar[];

  // コンストラクタ。1文字ずつFactoryにBigCharを問い合わせる。
  // 同じ数字が複数回登場しても、ここで生成されるのは種類の数だけ
  // (残りはFactoryが共有インスタンスを返す)。
  constructor(digits: string) {
    const factory = BigCharFactory.getInstance();
    this.bigchars = [...digits].map((ch) => factory.getBigChar(ch));
  }

  // 表示
  print(): void {
    for (const bc of this.bigchars) {
      bc.print();
    }
  }
}
main.ts
// Flyweight パターン: 大きな文字列表示 (Java版と同じ題材)
//
// 実行:
//   npx tsx GoF/patterns/Flyweight/typescript/main.ts 1212123
//
// Java版と同じお題: 引数の数字文字列を1文字ずつ「大きな文字」に変換して表示する。
// BigCharFactoryが同じ文字のBigCharインスタンスをキャッシュ・共有するので、
// 例えば "1212123" のように同じ数字(1, 2)が複数回出てくると、
// 2回目以降は新規生成せず使い回したことがコンソールログでわかる(Go版main.goと同じ構成)。

import { BigString } from "./big_string";

function main(): void {
  const args = process.argv.slice(2);
  if (args.length !== 1) {
    console.error("Usage: npx tsx GoF/patterns/Flyweight/typescript/main.ts digits");
    console.error("Example: npx tsx GoF/patterns/Flyweight/typescript/main.ts 1212123");
    process.exit(0);
  }

  const bs = new BigString(args[0]);
  console.log();
  bs.print();
}

main();
big0.txt
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
big1.txt
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
big2.txt
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
big3.txt
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
big4.txt
........##......
......####......
....##..##......
..##....##......
..##########....
........##......
......######....
................
big5.txt
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
big6.txt
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
big7.txt
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
big8.txt
....######......
..##......##....
..##......##....
....######......
..##......##....
..##......##....
....######......
................
big9.txt
....######......
..##......##....
..##......##....
....########....
..........##....
..##......##....
....######......
................
big-.txt
................
................
................
................
..##########....
................
................
................
Python

Go/TS版と同じ構成。

実行: python3 GoF/patterns/Flyweight/python/main.py 1212123

$ python3 GoF/patterns/Flyweight/python/main.py 1212123
big_char.py
"""BigChar: Flyweightそのもの。1文字ぶんの「大きな文字」を表す。

charname(intrinsic state)が同じならfontdataの中身も必ず同じになるため、
BigCharFactoryが使い回しても問題が起きない(=共有安全)。
"""

from __future__ import annotations

from pathlib import Path


class BigChar:
    def __init__(self, charname: str, font_dir: Path) -> None:
        """コンストラクタ。font_dir配下の"big<charname>.txt"を読む。

        Java版はカレントディレクトリから直接読むが、Python版はどこから実行しても
        動くよう、呼び出し元(BigCharFactory)からfont_dirを渡してもらう。
        """
        self._charname = charname
        try:
            raw = (font_dir / f"big{charname}.txt").read_text(encoding="utf-8")
            self._fontdata = raw.replace("\r\n", "\n")
        except OSError:
            self._fontdata = f"{charname}?"

    def print(self) -> None:
        """大きな文字を表示する"""
        print(self._fontdata, end="")
big_char_factory.py
"""BigCharFactory: Flyweightを生成・共有する工場(FlyweightFactory)。

同じcharnameを渡された場合は新規生成せず、poolに貯めた既存インスタンスを返す。
ここがFlyweightパターンの本質=「同じものは1つだけ作って使い回す」。
"""

from __future__ import annotations

from pathlib import Path

from big_char import BigChar

# このソースファイル自身が置かれているディレクトリ。
# `python3 GoF/patterns/Flyweight/python/main.py 1212123` のように
# リポジトリルートから実行しても、big<N>.txtをカレントディレクトリ非依存で
# 見つけられるようにするため、__file__から解決する(Go版のruntime.Caller相当)。
_FONT_DIR = Path(__file__).resolve().parent


class BigCharFactory:
    _singleton: BigCharFactory | None = None

    def __init__(self) -> None:
        self._pool: dict[str, BigChar] = {}

    @classmethod
    def get_instance(cls) -> BigCharFactory:
        """唯一のインスタンスを得る(Singletonパターン)。"""
        if cls._singleton is None:
            cls._singleton = BigCharFactory()
        return cls._singleton

    def get_big_char(self, charname: str) -> BigChar:
        """charname1文字ぶんのBigCharを返す(生成 or 共有)。"""
        cached = self._pool.get(charname)
        if cached is not None:
            print(
                f"[BigCharFactory] 共有: '{charname}' は既存のインスタンスを再利用します "
                f"(pool size={len(self._pool)})"
            )
            return cached

        bc = BigChar(charname, _FONT_DIR)  # ここでBigCharのインスタンスを生成
        self._pool[charname] = bc
        print(
            f"[BigCharFactory] 生成: '{charname}' の新しいインスタンスを作成しました "
            f"(pool size={len(self._pool)})"
        )
        return bc
big_string.py
"""BigString: 「大きな文字」の並び。BigCharという小さなFlyweightの集合として
1つの大きな文字列を表す。
"""

from __future__ import annotations

from big_char_factory import BigCharFactory


class BigString:
    def __init__(self, digits: str) -> None:
        """コンストラクタ。1文字ずつFactoryにBigCharを問い合わせる。

        同じ数字が複数回登場しても、ここで生成されるのは種類の数だけ
        (残りはFactoryが共有インスタンスを返す)。
        """
        factory = BigCharFactory.get_instance()
        self._bigchars = [factory.get_big_char(ch) for ch in digits]

    def print(self) -> None:
        """表示"""
        for bc in self._bigchars:
            bc.print()
main.py
"""Flyweight パターン: 大きな文字列表示 (Java版と同じ題材)

実行:
    python3 GoF/patterns/Flyweight/python/main.py 1212123

Java版と同じお題: 引数の数字文字列を1文字ずつ「大きな文字」に変換して表示する。
BigCharFactoryが同じ文字のBigCharインスタンスをキャッシュ・共有するので、
例えば "1212123" のように同じ数字(1, 2)が複数回出てくると、
2回目以降は新規生成せず使い回したことがコンソールログでわかる(Go/TS版main.goと同じ構成)。
"""

from __future__ import annotations

import sys

from big_string import BigString


def main() -> None:
    if len(sys.argv) != 2:
        print("Usage: python3 GoF/patterns/Flyweight/python/main.py digits")
        print("Example: python3 GoF/patterns/Flyweight/python/main.py 1212123")
        sys.exit(0)

    bs = BigString(sys.argv[1])
    print()
    bs.print()


if __name__ == "__main__":
    main()
big0.txt
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
big1.txt
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
big2.txt
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
big3.txt
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
big4.txt
........##......
......####......
....##..##......
..##....##......
..##########....
........##......
......######....
................
big5.txt
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
big6.txt
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
big7.txt
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
big8.txt
....######......
..##......##....
..##......##....
....######......
..##......##....
..##......##....
....######......
................
big9.txt
....######......
..##......##....
..##......##....
....########....
..........##....
..##......##....
....######......
................
big-.txt
................
................
................
................
..##########....
................
................
................