// 享元类包含一个树的部分状态。这些成员变量保存的数值对于特定树而言是唯一 // 的。例如,你在这里找不到树的坐标。但这里有很多树木之间所共有的纹理和颜 // 色。由于这些数据的体积通常非常大,所以如果让每棵树都其进行保存的话将耗 // 费大量内存。因此,我们可将纹理、颜色和其他重复数据导出到一个单独的对象 // 中,然后让众多的单个树对象去引用它。 class TreeType is field name field color field texture constructorTreeType(name, color, texture){ ... } methoddraw(canvas, x, y)is // 1. 创建特定类型、颜色和纹理的位图。 // 2. 在画布坐标 (X,Y) 处绘制位图。 // 享元工厂决定是否复用已有享元或者创建一个新的对象。 classTreeFactoryis staticfieldtreeTypes: collection of tree types static method getTreeType(name, color, texture) is type = treeTypes.find(name, color, texture) if (type == null) type = new TreeType(name, color, texture) treeTypes.add(type) return type
// 情景对象包含树状态的外在部分。程序中可以创建数十亿个此类对象,因为它们 // 体积很小:仅有两个整型坐标和一个引用成员变量。 class Tree is field x,y field type: TreeType constructorTree(x, y, type){ ... } methoddraw(canvas)is type.draw(canvas, this.x, this.y) // 树(Tree)和森林(Forest)类是享元的客户端。如果不打算继续对树类进行开 // 发,你可以将它们合并。 classForestis fieldtrees: collection of Trees
method plantTree(x, y, name, color, texture) is type = TreeFactory.getTreeType(name, color, texture) tree = new Tree(x, y, type) trees.add(tree)
method draw(canvas) is foreach (tree in trees) do tree.draw(canvas)
using System; using System.Collections.Generic; using System.Linq; // Use Json.NET library, you can download it from NuGet Package Manager using Newtonsoft.Json;
namespaceRefactoringGuru.DesignPatterns.Flyweight.Conceptual { // The Flyweight stores a common portion of the state (also called intrinsic // state) that belongs to multiple real business entities. The Flyweight // accepts the rest of the state (extrinsic state, unique for each entity) // via its method parameters. publicclassFlyweight { private Car _sharedState;
publicvoidOperation(Car uniqueState) { string s = JsonConvert.SerializeObject(this._sharedState); string u = JsonConvert.SerializeObject(uniqueState); Console.WriteLine($"Flyweight: Displaying shared {s} and unique {u} state."); } }
// The Flyweight Factory creates and manages the Flyweight objects. It // ensures that flyweights are shared correctly. When the client requests a // flyweight, the factory either returns an existing instance or creates a // new one, if it doesn't exist yet. publicclassFlyweightFactory { private List<Tuple<Flyweight, string>> flyweights = new List<Tuple<Flyweight, string>>();
// Returns an existing Flyweight with a given state or creates a new // one. public Flyweight GetFlyweight(Car sharedState) { string key = this.getKey(sharedState);
publicvoidlistFlyweights() { var count = flyweights.Count; Console.WriteLine($"\nFlyweightFactory: I have {count} flyweights:"); foreach (var flyweight in flyweights) { Console.WriteLine(flyweight.Item2); } } }
publicclassCar { publicstring Owner { get; set; }
publicstring Number { get; set; }
publicstring Company { get; set; }
publicstring Model { get; set; }
publicstring Color { get; set; } }
classProgram { staticvoidMain(string[] args) { // The client code usually creates a bunch of pre-populated // flyweights in the initialization stage of the application. var factory = new FlyweightFactory( new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" }, new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" }, new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" }, new Car { Company = "BMW", Model = "M5", Color = "red" }, new Car { Company = "BMW", Model = "X6", Color = "white" } ); factory.listFlyweights();
addCarToPoliceDatabase(factory, new Car { Number = "CL234IR", Owner = "James Doe", Company = "BMW", Model = "M5", Color = "red" });
addCarToPoliceDatabase(factory, new Car { Number = "CL234IR", Owner = "James Doe", Company = "BMW", Model = "X1", Color = "red" });
factory.listFlyweights(); }
publicstaticvoidaddCarToPoliceDatabase(FlyweightFactory factory, Car car) { Console.WriteLine("\nClient: Adding a car to database.");
var flyweight = factory.GetFlyweight(new Car { Color = car.Color, Model = car.Model, Company = car.Company });
// The client code either stores or calculates extrinsic state and // passes it to the flyweight's methods. flyweight.Operation(car); } } }
FlyweightFactory: I have 5 flyweights: Camaro2018_Chevrolet_pink black_C300_Mercedes Benz C500_Mercedes Benz_red BMW_M5_red BMW_white_X6
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"M5","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"M5","Color":"red"} state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"X1","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"X1","Color":"red"} state.
FlyweightFactory: I have 6 flyweights: Camaro2018_Chevrolet_pink black_C300_Mercedes Benz C500_Mercedes Benz_red BMW_M5_red BMW_white_X6 BMW_red_X1
/** * Flyweight Design Pattern * * Intent: Lets you fit more objects into the available amount of RAM by sharing * common parts of state between multiple objects, instead of keeping all of the * data in each object. */
/** * The Flyweight stores a common portion of the state (also called intrinsic * state) that belongs to multiple real business entities. The Flyweight accepts * the rest of the state (extrinsic state, unique for each entity) via its * method parameters. */ classFlyweight { private: SharedState *shared_state_;
public: Flyweight(const SharedState *shared_state) : shared_state_(newSharedState(*shared_state)) { } Flyweight(const Flyweight &other) : shared_state_(newSharedState(*other.shared_state_)) { } ~Flyweight() { delete shared_state_; } SharedState *shared_state()const { return shared_state_; } voidOperation(const UniqueState &unique_state)const { std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n"; } }; /** * The Flyweight Factory creates and manages the Flyweight objects. It ensures * that flyweights are shared correctly. When the client requests a flyweight, * the factory either returns an existing instance or creates a new one, if it * doesn't exist yet. */ classFlyweightFactory { /** * @var Flyweight[] */ private: std::unordered_map<std::string, Flyweight> flyweights_; /** * Returns a Flyweight's string hash for a given state. */ std::string GetKey(const SharedState &ss)const { return ss.brand_ + "_" + ss.model_ + "_" + ss.color_; }
FlyweightFactory: I have 5 flyweights: BMW_X6_white Mercedes Benz_C500_red Mercedes Benz_C300_black BMW_M5_red Chevrolet_Camaro2018_pink
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared ([ BMW , M5 , red ]) and unique ([ CL234IR , James Doe ]) state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared ([ BMW , X1 , red ]) and unique ([ CL234IR , James Doe ]) state.
FlyweightFactory: I have 6 flyweights: BMW_X1_red Mercedes Benz_C300_black BMW_X6_white Mercedes Benz_C500_red BMW_M5_red Chevrolet_Camaro2018_pink
publicclassForestextendsJFrame { private List<Tree> trees = newArrayList<>();
publicvoidplantTree(int x, int y, String name, Color color, String otherTreeData) { TreeTypetype= TreeFactory.getTreeType(name, color, otherTreeData); Treetree=newTree(x, y, type); trees.add(tree); }
@Override publicvoidpaint(Graphics graphics) { for (Tree tree : trees) { tree.draw(graphics); } } }
/** * The Flyweight stores a common portion of the state (also called intrinsic * state) that belongs to multiple real business entities. The Flyweight accepts * the rest of the state (extrinsic state, unique for each entity) via its * method parameters. */ classFlyweight { private$sharedState;
/** * The Flyweight Factory creates and manages the Flyweight objects. It ensures * that flyweights are shared correctly. When the client requests a flyweight, * the factory either returns an existing instance or creates a new one, if it * doesn't exist yet. */ classFlyweightFactory { /** * @var Flyweight[] */ private$flyweights = [];
/** * Returns a Flyweight's string hash for a given state. */ privatefunctiongetKey(array$state): string { ksort($state);
returnimplode("_", $state); }
/** * Returns an existing Flyweight with a given state or creates a new one. */ publicfunctiongetFlyweight(array$sharedState): Flyweight { $key = $this->getKey($sharedState);
if (!isset($this->flyweights[$key])) { echo"FlyweightFactory: Can't find a flyweight, creating new one.\n"; $this->flyweights[$key] = newFlyweight($sharedState); } else { echo"FlyweightFactory: Reusing existing flyweight.\n"; }
/** * The client code usually creates a bunch of pre-populated flyweights in the * initialization stage of the application. */ $factory = newFlyweightFactory([ ["Chevrolet", "Camaro2018", "pink"], ["Mercedes Benz", "C300", "black"], ["Mercedes Benz", "C500", "red"], ["BMW", "M5", "red"], ["BMW", "X6", "white"], // ... ]); $factory->listFlyweights();
// ...
functionaddCarToPoliceDatabase( FlyweightFactory $ff, $plates, $owner, $brand, $model, $color ) { echo"\nClient: Adding a car to database.\n"; $flyweight = $ff->getFlyweight([$brand, $model, $color]);
// The client code either stores or calculates extrinsic state and passes it // to the flyweight's methods. $flyweight->operation([$plates, $owner]); }
FlyweightFactory: I have 5 flyweights: Chevrolet_Camaro2018_pink Mercedes Benz_C300_black Mercedes Benz_C500_red BMW_M5_red BMW_X6_white
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared (["BMW","M5","red"]) and unique (["CL234IR","James Doe"]) state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared (["BMW","X1","red"]) and unique (["CL234IR","James Doe"]) state.
FlyweightFactory: I have 6 flyweights: Chevrolet_Camaro2018_pink Mercedes Benz_C300_black Mercedes Benz_C500_red BMW_M5_red BMW_X6_white BMW_X1_red
/** * Flyweight objects represent the data shared by multiple Cat objects. This is * the combination of breed, color, texture, etc. */ classCatVariation { /** * The so-called "intrinsic" state. */ public$breed;
/** * This method displays the cat information. The method accepts the * extrinsic state as arguments. The rest of the state is stored inside * Flyweight's fields. * * You might be wondering why we had put the primary cat's logic into the * CatVariation class instead of keeping it in the Cat class. I agree, it * does sound confusing. * * Keep in mind that in the real world, the Flyweight pattern can either be * implemented from the start or forced onto an existing application * whenever the developers realize they've hit upon a RAM problem. * * In the latter case, you end up with such classes as we have here. We kind * of "refactored" an ideal app where all the data was initially inside the * Cat class. If we had implemented the Flyweight from the start, our class * names might be different and less confusing. For example, Cat and * CatContext. * * However, the actual reason why the primary behavior should live in the * Flyweight class is that you might not have the Context class declared at * all. The context data might be stored in an array or some other more * efficient data structure. You won't have another place to put your * methods in, except the Flyweight class. */ publicfunctionrenderProfile(string$name, string$age, string$owner) { echo"= $name =\n"; echo"Age: $age\n"; echo"Owner: $owner\n"; echo"Breed: $this->breed\n"; echo"Image: $this->image\n"; echo"Color: $this->color\n"; echo"Texture: $this->texture\n"; } }
/** * The context stores the data unique for each cat. * * A designated class for storing context is optional and not always viable. The * context may be stored inside a massive data structure within the Client code * and passed to the flyweight methods when needed. */ classCat { /** * The so-called "extrinsic" state. */ public$name;
/** * Since the Context objects don't own all of their state, sometimes, for * the sake of convenience, you may need to implement some helper methods * (for example, for comparing several Context objects.) */ publicfunctionmatches(array$query): bool { foreach ($queryas$key => $value) { if (property_exists($this, $key)) { if ($this->$key != $value) { returnfalse; } } elseif (property_exists($this->variation, $key)) { if ($this->variation->$key != $value) { returnfalse; } } else { returnfalse; } }
returntrue; }
/** * The Context might also define several shortcut methods, that delegate * execution to the Flyweight object. These methods might be remnants of * real methods, extracted to the Flyweight class during a massive * refactoring to the Flyweight pattern. */ publicfunctionrender(): string { $this->variation->renderProfile($this->name, $this->age, $this->owner); } }
/** * The Flyweight Factory stores both the Context and Flyweight objects, * effectively hiding any notion of the Flyweight pattern from the client. */ classCatDataBase { /** * The list of cat objects (Contexts). */ private$cats = [];
/** * The list of cat variations (Flyweights). */ private$variations = [];
/** * When adding a cat to the database, we look for an existing cat variation * first. */ publicfunctionaddCat( string$name, string$age, string$owner, string$breed, string$image, string$color, string$texture, string$fur, string$size ) { $variation = $this->getVariation($breed, $image, $color, $texture, $fur, $size); $this->cats[] = newCat($name, $age, $owner, $variation); echo"CatDataBase: Added a cat ($name, $breed).\n"; }
/** * Return an existing variation (Flyweight) by given data or create a new * one if it doesn't exist yet. */ publicfunctiongetVariation( string$breed, string$image, $color, string$texture, string$fur, string$size ): CatVariation{ $key = $this->getKey(get_defined_vars());
/** * This function helps to generate unique array keys. */ privatefunctiongetKey(array$data): string { returnmd5(implode("_", $data)); }
/** * Look for a cat in the database using the given query parameters. */ publicfunctionfindCat(array$query) { foreach ($this->cats as$cat) { if ($cat->matches($query)) { return$cat; } } echo"CatDataBase: Sorry, your query does not yield any results."; } }
/** * The client code. */ $db = newCatDataBase();
echo"Client: Let's see what we have in \"cats.csv\".\n";
// To see the real effect of the pattern, you should have a large database with // several millions of records. Feel free to experiment with code to see the // real extent of the pattern. $handle = fopen(__DIR__ . "/cats.csv", "r"); $row = 0; $columns = []; while (($data = fgetcsv($handle)) !== false) { if ($row == 0) { for ($c = 0; $c < count($data); $c++) { $columnIndex = $c; $columnKey = strtolower($data[$c]); $columns[$columnKey] = $columnIndex; } $row++; continue; }
echo"\nClient: Let's look for a cat named \"Siri\".\n"; $cat = $db->findCat(['name' => "Siri"]); if ($cat) { $cat->render(); }
echo"\nClient: Let's look for a cat named \"Bob\".\n"; $cat = $db->findCat(['name' => "Bob"]); if ($cat) { $cat->render(); }
Output.txt: 执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Client: Let's see what we have in "cats.csv". CatDataBase: Added a cat (Steve, Bengal). CatDataBase: Added a cat (Siri, Domestic short-haired). CatDataBase: Added a cat (Fluffy, Maine Coon).
Client: Let's look for a cat named "Siri". = Siri = Age: 2 Owner: Alexander Shvets Breed: Domestic short-haired Image: /cats/domestic-sh.jpg Color: Black Texture: Solid
Client: Let's look for a cat named "Bob". CatDataBase: Sorry, your query does not yield any results.
classFlyweight(): """ The Flyweight stores a common portion of the state (also called intrinsic state) that belongs to multiple real business entities. The Flyweight accepts the rest of the state (extrinsic state, unique for each entity) via its method parameters. """
defoperation(self, unique_state: str) -> None: s = json.dumps(self._shared_state) u = json.dumps(unique_state) print(f"Flyweight: Displaying shared ({s}) and unique ({u}) state.", end="")
classFlyweightFactory(): """ The Flyweight Factory creates and manages the Flyweight objects. It ensures that flyweights are shared correctly. When the client requests a flyweight, the factory either returns an existing instance or creates a new one, if it doesn't exist yet. """
_flyweights: Dict[str, Flyweight] = {}
def__init__(self, initial_flyweights: Dict) -> None: for state in initial_flyweights: self._flyweights[self.get_key(state)] = Flyweight(state)
defget_key(self, state: Dict) -> str: """ Returns a Flyweight's string hash for a given state. """
return"_".join(sorted(state))
defget_flyweight(self, shared_state: Dict) -> Flyweight: """ Returns an existing Flyweight with a given state or creates a new one. """
key = self.get_key(shared_state)
ifnot self._flyweights.get(key): print("FlyweightFactory: Can't find a flyweight, creating new one.") self._flyweights[key] = Flyweight(shared_state) else: print("FlyweightFactory: Reusing existing flyweight.")
return self._flyweights[key]
deflist_flyweights(self) -> None: count = len(self._flyweights) print(f"FlyweightFactory: I have {count} flyweights:") print("\n".join(map(str, self._flyweights.keys())), end="")
defadd_car_to_police_database( factory: FlyweightFactory, plates: str, owner: str, brand: str, model: str, color: str ) -> None: print("\n\nClient: Adding a car to database.") flyweight = factory.get_flyweight([brand, model, color]) # The client code either stores or calculates extrinsic state and passes it # to the flyweight's methods. flyweight.operation([plates, owner])
if __name__ == "__main__": """ The client code usually creates a bunch of pre-populated flyweights in the initialization stage of the application. """
FlyweightFactory: I have 5 flyweights: Camaro2018_Chevrolet_pink C300_Mercedes Benz_black C500_Mercedes Benz_red BMW_M5_red BMW_X6_white
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared (["BMW", "M5", "red"]) and unique (["CL234IR", "James Doe"]) state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared (["BMW", "X1", "red"]) and unique (["CL234IR", "James Doe"]) state.
FlyweightFactory: I have 6 flyweights: Camaro2018_Chevrolet_pink C300_Mercedes Benz_black C500_Mercedes Benz_red BMW_M5_red BMW_X6_white BMW_X1_red
# The Flyweight stores a common portion of the state (also called intrinsic # state) that belongs to multiple real business entities. The Flyweight accepts # the rest of the state (extrinsic state, unique for each entity) via its method # parameters. classFlyweight # @param [String] shared_state definitialize(shared_state) @shared_state = shared_state end
# @param [String] unique_state defoperation(unique_state) s = @shared_state.to_json u = unique_state.to_json print "Flyweight: Displaying shared (#{s}) and unique (#{u}) state." end end
# The Flyweight Factory creates and manages the Flyweight objects. It ensures # that flyweights are shared correctly. When the client requests a flyweight, # the factory either returns an existing instance or creates a new one, if it # doesn't exist yet. classFlyweightFactory # @param [Hash] initial_flyweights definitialize(initial_flyweights) @flyweights = {} initial_flyweights.each do |state| @flyweights[get_key(state)] = Flyweight.new(state) end end
# Returns a Flyweight's string hash for a given state. defget_key(state) state.sort.join('_') end
# Returns an existing Flyweight with a given state or creates a new one. defget_flyweight(shared_state) key = get_key(shared_state)
if !@flyweights.key?(key) puts "FlyweightFactory: Can't find a flyweight, creating new one." @flyweights[key] = Flyweight.new(shared_state) else puts 'FlyweightFactory: Reusing existing flyweight.' end
@flyweights[key] end
deflist_flyweights puts "FlyweightFactory: I have #{@flyweights.size} flyweights:" print @flyweights.keys.join("\n") end end
# @param [FlyweightFactory] factory # @param [String] plates # @param [String] owner # @param [String] brand # @param [String] model # @param [String] color defadd_car_to_police_database(factory, plates, owner, brand, model, color) puts "\n\nClient: Adding a car to database." flyweight = factory.get_flyweight([brand, model, color]) # The client code either stores or calculates extrinsic state and passes it to # the flyweight's methods. flyweight.operation([plates, owner]) end
# The client code usually creates a bunch of pre-populated flyweights in the # initialization stage of the application.
FlyweightFactory: I have 5 flyweights: Camaro2018_Chevrolet_pink C300_Mercedes Benz_black C500_Mercedes Benz_red BMW_M5_red BMW_X6_white
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared (["BMW","M5","red"]) and unique (["CL234IR","James Doe"]) state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared (["BMW","X1","red"]) and unique (["CL234IR","James Doe"]) state.
FlyweightFactory: I have 6 flyweights: Camaro2018_Chevrolet_pink C300_Mercedes Benz_black C500_Mercedes Benz_red BMW_M5_red BMW_X6_white BMW_X1_red
/// The Flyweight stores a common portion of the state (also called intrinsic /// state) that belongs to multiple real business entities. The Flyweight /// accepts the rest of the state (extrinsic state, unique for each entity) via /// its method parameters. classFlyweight {
/// The Flyweight Factory creates and manages the Flyweight objects. It ensures /// that flyweights are shared correctly. When the client requests a flyweight, /// the factory either returns an existing instance or creates a new one, if it /// doesn't exist yet. classFlyweightFactory {
privatevar flyweights: [String: Flyweight]
init(states: [[String]]) {
var flyweights = [String: Flyweight]()
for state in states { flyweights[state.key] =Flyweight(sharedState: state) }
self.flyweights = flyweights }
/// Returns an existing Flyweight with a given state or creates a new one. funcflyweight(forstate: [String]) -> Flyweight {
let key = state.key
guardlet foundFlyweight = flyweights[key] else {
print("FlyweightFactory: Can't find a flyweight, creating new one.\n") let flyweight =Flyweight(sharedState: state) flyweights.updateValue(flyweight, forKey: key) return flyweight } print("FlyweightFactory: Reusing existing flyweight.\n") return foundFlyweight }
funcprintFlyweights() { print("FlyweightFactory: I have \(flyweights.count) flyweights:\n") for item in flyweights { print(item.key) } } }
extensionArraywhereElement == String {
/// Returns a Flyweight's string hash for a given state. var key: String { returnself.joined() } }
classFlyweightConceptual: XCTestCase {
functestFlyweight() {
/// The client code usually creates a bunch of pre-populated flyweights /// in the initialization stage of the application.
let flyweight = factory.flyweight(for: [brand, model, color])
/// The client code either stores or calculates extrinsic state and /// passes it to the flyweight's methods. flyweight.operation(uniqueState: [plates, owner]) } }
let maineCoon =Animal(name: "Maine Coon", country: "USA", type: .cat)
let sphynx =Animal(name: "Sphynx", country: "Egypt", type: .cat)
let bulldog =Animal(name: "Bulldog", country: "England", type: .dog)
print("Client: I created a number of objects to display")
/// Displaying objects for the 1-st time.
print("Client: Let's show animals for the 1st time\n") display(animals: [maineCoon, sphynx, bulldog])
/// Displaying objects for the 2-nd time. /// /// Note: Cached object of the appearance will be reused this time.
print("\nClient: I have a new dog, let's show it the same way!\n")
let germanShepherd =Animal(name: "German Shepherd", country: "Germany", type: .dog)
display(animals: [germanShepherd]) } }
extensionFlyweightRealWorld {
funcdisplay(animals: [Animal]) {
let cells = loadCells(count: animals.count)
for index in0..<animals.count { cells[index].update(with: animals[index]) }
/// Using cells... }
funcloadCells(count: Int) -> [Cell] { /// Emulates behavior of a table/collection view. returnArray(repeating: Cell(), count: count) } }
enumType: String { case cat case dog }
classCell {
privatevar animal: Animal?
funcupdate(withanimal: Animal) { self.animal = animal let type = animal.type.rawValue let photos ="photos \(animal.appearance.photos.count)" print("Cell: Updating an appearance of a \(type)-cell: \(photos)\n") } }
structAnimal: Equatable {
/// This is an external context that contains specific values and an object /// with a common state. /// /// Note: The object of appearance will be lazily created when it is needed
let name: String let country: String let type: Type
var appearance: Appearance { returnAppearanceFactory.appearance(for: type) } }
structAppearance: Equatable {
/// This object contains a predefined appearance of every cell
let photos: [UIImage] let backgroundColor: UIColor }
/** * The Flyweight stores a common portion of the state (also called intrinsic * state) that belongs to multiple real business entities. The Flyweight accepts * the rest of the state (extrinsic state, unique for each entity) via its * method parameters. */ classFlyweight { privatesharedState: any;
publicoperation(uniqueState): void { const s = JSON.stringify(this.sharedState); const u = JSON.stringify(uniqueState); console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`); } }
/** * The Flyweight Factory creates and manages the Flyweight objects. It ensures * that flyweights are shared correctly. When the client requests a flyweight, * the factory either returns an existing instance or creates a new one, if it * doesn't exist yet. */ classFlyweightFactory { privateflyweights: {[key: string]: Flyweight} = <any>{};
constructor(initialFlyweights: string[][]) { for (const state of initialFlyweights) { this.flyweights[this.getKey(state)] = newFlyweight(state); } }
/** * Returns a Flyweight's string hash for a given state. */ privategetKey(state: string[]): string { return state.join('_'); }
/** * Returns an existing Flyweight with a given state or creates a new one. */ publicgetFlyweight(sharedState: string[]): Flyweight { const key = this.getKey(sharedState);
if (!(key inthis.flyweights)) { console.log('FlyweightFactory: Can\'t find a flyweight, creating new one.'); this.flyweights[key] = newFlyweight(sharedState); } else { console.log('FlyweightFactory: Reusing existing flyweight.'); }
returnthis.flyweights[key]; }
publiclistFlyweights(): void { const count = Object.keys(this.flyweights).length; console.log(`\nFlyweightFactory: I have ${count} flyweights:`); for (const key inthis.flyweights) { console.log(key); } } }
/** * The client code usually creates a bunch of pre-populated flyweights in the * initialization stage of the application. */ const factory = newFlyweightFactory([ ['Chevrolet', 'Camaro2018', 'pink'], ['Mercedes Benz', 'C300', 'black'], ['Mercedes Benz', 'C500', 'red'], ['BMW', 'M5', 'red'], ['BMW', 'X6', 'white'], // ... ]); factory.listFlyweights();
// ...
functionaddCarToPoliceDatabase( ff: FlyweightFactory, plates: string, owner: string, brand: string, model: string, color: string, ) { console.log('\nClient: Adding a car to database.'); const flyweight = ff.getFlyweight([brand, model, color]);
// The client code either stores or calculates extrinsic state and passes it // to the flyweight's methods. flyweight.operation([plates, owner]); }
FlyweightFactory: I have 5 flyweights: Chevrolet_Camaro2018_pink Mercedes Benz_C300_black Mercedes Benz_C500_red BMW_M5_red BMW_X6_white
Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared (["BMW","M5","red"]) and unique (["CL234IR","James Doe"]) state.
Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared (["BMW","X1","red"]) and unique (["CL234IR","James Doe"]) state.
FlyweightFactory: I have 6 flyweights: Chevrolet_Camaro2018_pink Mercedes Benz_C300_black Mercedes Benz_C500_red BMW_M5_red BMW_X6_white BMW_X1_red