100 likes | 244 Views
Structural Pattern: Flyweight. Chapter 4 – Page 109. To maximize flexibility, it is often advantageous to model objects down to very fine levels of granularity.
E N D
Structural Pattern: Flyweight Chapter 4 – Page 109 To maximize flexibility, it is often advantageous to model objects down to very fine levels of granularity. However, when very large numbers of such objects are needed in an application, this level of granularity can be prohibitively expensive in terms of performance and memory usage. The Flyweight Pattern tackles this problem by splitting the objects into their extrinsic (i.e., state-dependent) and intrinsic (state-independent) components. The intrinsic parts are shared within the Flyweight object, while the extrinsic parts are controlled by the client and passed to the Flyweight as needed.
The Flyweight Pattern Chapter 4 – Page 110 The Client maintains a reference to the Flyweight objects and computes or stores their extrinsic state. The FlyweightFactory creates and manages the Flyweight objects, ensuring proper sharing (i.e., if a client needs a Flyweight, the FlyweightFactory supplies an existing one or, if none exists, creates a new one). The Flyweight declares an interface through which the concrete Flyweight objects can deal with their extrinsic state. The ConcreteFlyweight implements the Flyweight interface and adds storage for its intrinsic state; although the Flyweight interface enables sharing, UnsharedConcreteFlyweight objects may exist.
Non-Software Flyweight Example Chapter 4 – Page 111 The public switched telephone network is an example of a Flyweight. There are several resources (ConcreteFlyweights) such as dial tone generators, ringing generators, and digit receivers that must be shared between all subscribers. A subscriber (the Client) is unaware of how many resources are in the pool when he or she lifts the handset to make a call. All that matters to subscribers is that a dial tone is provided, digits are received, and the call is completed.
C++ Flyweight Pattern Example Chapter 4 – Page 112 /* Network links are the Flyweight objects here, with the technology type being used (e.g., */ /* MPLS, BGP) as their intrinsic features and their adjacent nodes (types include core routers, */ /* provider-edge routers, and subscriber-edge routers), adjacent interfaces (types include IP, */ /* ATM, etc.), and IP address ranges as their extrinsic features. */ /* */ /* When each link in the network is capable of supporting several IP addresss, specific IP */ /* addresses must be assigned to the interfaces supported by the links between adjacent nodes, */ /* which, for elaborate networks, can become a prohibitive task. */ #include <iostream> #include <string> #include "RealLink.h" using namespace std; void main() { GenericLinkContext* aLinkContext = newGenericLinkContext(); RealLink* aLink = newRealLink("MPLS", "Core Router A", "Core Router B", "Interface IP", "Interface ATM", aLinkContext); RealLink* anotherLink = newRealLink("BGP", "Core Router X", "Edge Router Y", "Interface ATM", "Interface IP", aLinkContext); aLinkContext->SetAddressRange(anotherLink->mySlotNumber, "11.61.1.x", 6, 9); aLinkContext->SetAddressRange(aLink->mySlotNumber, "10.81.1.x", 0, 7); cout<< "For the " << aLink->GetTechnologyType() << " link, the IP Address range is " << aLink->GetAllIPAddresses() << endl << endl; cout<< "For the " << anotherLink->GetTechnologyType() << " link, the IP Address range is " << anotherLink->GetAllIPAddresses() << endl << endl; }
Chapter 4 – Page 113 #include <string> using namespace std; classGenericLinkContext { public: explicitGenericLinkContext() { SetNextFreeSlot(-1); } virtual~GenericLinkContext() {} virtualintGetNextFreeSlot() { if(nextFreeSlot < MAX_ARRAY_LENGTH) return++nextFreeSlot; else return nextFreeSlot; } virtual void SetNextFreeSlot(inttheNextFreeSlot) { nextFreeSlot = theNextFreeSlot; } virtual void SetAddressRange(int slot, string baseAddress, int offset, int range) { AddressRangeArray[slot].baseRangeAddress = baseAddress; AddressRangeArray[slot].addressOffset = offset; AddressRangeArray[slot].addressRange = range; } virtualstring GetBaseAddress(int slot) { returnAddressRangeArray[slot].baseRangeAddress; } virtual intGetAddressOffset(int slot) { returnAddressRangeArray[slot].addressOffset; } virtual intGetAddressRange(int slot) { returnAddressRangeArray[slot].addressRange; } private: intnextFreeSlot; static const intMAX_ARRAY_LENGTH = 10; /* Each entry in the array AddressRangeArray stores the IP address range details */ /* for a given link. Each link has an associated slot in this array. So when a new */ /* link must be created with a specific IP address range, the nextFreeSlot value */ /* is retrieved by invoking GetNextFreeSlot(). If the value is less than the */ /* maximum (10), a new address range array slot will be allocated. Once this new */ /* slot is obtained, the IP address range can be supplied via SetAddressRange(). */ structAddressRanges { string baseRangeAddress; intaddressOffset; intaddressRange; } AddressRangeArray[MAX_ARRAY_LENGTH]; };
Chapter 4 – Page 114 #include "GenericLinkContext.h" #include <string> using namespace std; classGenericLink { public: explicitGenericLink(GenericLinkContext* aLinkContext, string nodeA, string nodeB, string ifA, string ifB) { linkContext= aLinkContext; mySlotNumber= linkContext->GetNextFreeSlot(); NodeA= nodeA; NodeB= nodeB; InterfaceA= ifA; InterfaceB= ifB; } virtual~GenericLink() {} protected: GenericLinkContext* linkContext; public: intmySlotNumber; private: string NodeA; string NodeB; string InterfaceA; // Each interface can support many IP addresses string InterfaceB; // Each interface can support many IP addresses };
#include "GenericLink.h" #include <string> using namespace std; classRealLink : publicGenericLink { public: explicitRealLink(string aTechnologyType, string nodeA, string nodeB, string ifA, string ifB, GenericLinkContext* aLinkContext): GenericLink(aLinkContext, nodeA, nodeB, ifA, ifB) { technologyType = aTechnologyType; } virtual~RealLink() {} string GetAllIPAddresses() { string ipAddressRange = ""; intaddressOffset = linkContext->GetAddressOffset(mySlotNumber); intaddressRange = linkContext->GetAddressRange(mySlotNumber); ipAddressRange= ipAddressRange + linkContext->GetBaseAddress(mySlotNumber) + " - " + linkContext->GetBaseAddress(mySlotNumber); intindex = 0; while(ipAddressRange[index] != 'x') index++; ipAddressRange[index] = addressOffset + '0'; while(ipAddressRange[index] != 'x') index++; ipAddressRange[index] = addressRange + '0'; returnipAddressRange; } string GetTechnologyType() { returntechnologyType; } private: string technologyType; }; Chapter 4 – Page 115
Flyweight Pattern Advantages Chapter 4 – Page 116 • There are cases in programming where it seems that a very large number of small class instances is needed to represent data. • If the instances are fundamentally the same except for a few parameters, the number of instantiations can be greatly reduced by means of the Flyweight Pattern. • Essentially, the variables that differ can be moved outside of the class instance and passed in as part of a method call. • While the Flyweight Pattern is not commonly used in application software, it does provide a useful technique for managing resources at the system level.