上一篇《原型模式》 下一篇《责任链模式》
简介:
享元模式,它是一种结构型设计模式,旨在有效地支持大量细粒度的对象共享,通过共享对象来减少内存消耗和提高性能。享元模式将对象的状态分为内部状态和外部状态。内部状态是对象的固定部分,可以在多个对象之间共享,而外部状态是对象的变化部分,需要在使用时传递给对象。享元模式将内部状态存储在享元对象中,并将外部状态作为参数传递给方法。
享元模式包含以下几个关键组件:
1、享元接口:定义了享元对象的通用接口,通过该接口可以获取内部状态和操作享元对象。
2、具体享元:实现了享元接口,并包含内部状态。具体享元对象需要是可共享的,也就是说它们可以在多个上下文中共享。
3、享元工厂:负责创建和管理享元对象。它维护一个享元池,用于存储已经创建的享元对象,以便在需要时进行复用。当客户端需要使用享元对象时,可以通过享元工厂获取对象的实例。如果享元池中已经存在相应的对象实例,则直接返回该实例;如果不存在,则创建一个新的享元对象并添加到享元池中。这样可以确保相同的对象在多个地方共享使用,减少内存消耗。
需要注意的是,当对象数量太多时,享元模式会导致运行代价过高,带来性能下降等问题。因此,在使用享元模式时,要根据实际情况慎重考虑。
享元模式的使用场景:
1、系统中存在大量的相似对象。
2、细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。
3、需要缓冲池的场景。
享元模式通过共享对象来减少内存消耗和提高性能,适用于存在大量相似对象的场景,特别是当对象的内部状态较少并且可以共享时。它常用于系统底层的开发,解决系统的性能问题,比如数据库连接池、String常量池、缓冲池等都是享元模式的使用。
虽然可以使用享元模式来实现对象池,但是这两者还是有比较大的差异。对象池着重在对象的复用上,池中的每个对象是可替换的,从同一个池中获得A对象和B对象对客户端来说是完全相同的;而享元模式主要解决的对象的共享问题,如何建立多个可共享的细粒度对象是其主要关注的重点。
享元模式的创建步骤:
1、定义抽象享元类:这是一个抽象类,内部状态和外部状态的定义,以及抽象方法的定义。抽象类通常用于声明享元工厂类和用户调用中涉及的对象类型。
2、定义内部状态:内部状态是多个细粒度对象共享的信息。这些信息是在对象池中维护一个享元对象的共享信息。当多个细粒度对象从享元工厂类中获取该享元对象时,它们获取的都是相同的享元对象。
3、定义外部状态:外部状态很重要,它作为从对象池中获取对象的依据。外部状态相等的两个对象说明它们是相同的。
4、创建享元工厂:负责维护享元池,用于存储具有相同内部状态的享元对象。享元模式中共享的仅仅是享元对象,外部状态是需要通过环境类设置的。
在实际使用中,能共享的内部状态不是很多的,所以设计享元对象是比较小的,也就是细粒度对象。所以说享元模式就是通过共享技术实现大量细粒度对象的复用。
享元模式的优点,主要包括:
1、减少内存消耗:享元模式通过共享对象实例来减少内存消耗,特别是在存在大量相似对象的场景中,可以显著降低内存消耗。
2、提高性能:由于享元对象是被共享的,所以它可以减少内存占用,从而降低系统的开销。同时,享元模式还可以提高系统的性能和效率。
3、提高系统的灵活性:享元模式将对象的内部状态和外部状态分离开来,使得系统更加易于扩展和维护。
享元模式的缺点,主要包括:
1、维护一个享元池需要引入额外的复杂性。在享元模式中,需要维护一个存储享元对象的享元池,这可能会增加系统的复杂性和开销。
2、为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。这可能会对系统的性能产生一定的影响。
3、享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。这可能会增加开发人员的工作量和开发难度。
4、享元模式不适用于所有情况。在某些情况下,使用享元模式可能会导致系统的设计和实现变得复杂化和难以理解,从而增加开发和维护的成本。
示例:
一、C#享元模式
以下是一个示例,展示了如何在C#中实现享元模式:
using System;
using System.Collections.Generic;
public abstract class Shape
{
protected int _x;
protected int _y;
public Shape(int x, int y)
{
_x = x;
_y = y;
}
public virtual void Draw()
{
Console.WriteLine("Drawing Shape at ({0}, {1})", _x, _y);
}
}
public class Circle : Shape
{
public Circle(int x, int y) : base(x, y) { }
public override void Draw()
{
Console.WriteLine("Drawing Circle at ({0}, {1})", _x, _y);
}
}
public class Rectangle : Shape
{
public Rectangle(int x, int y) : base(x, y) { }
public override void Draw()
{
Console.WriteLine("Drawing Rectangle at ({0}, {1})", _x, _y);
}
}
public class ShapeFactory
{
private Dictionary<string, Shape> _shapes = new Dictionary<string, Shape>();
public Shape GetShape(string shapeType)
{
if (_shapes.ContainsKey(shapeType))
{
return _shapes[shapeType];
}
else
{
Shape shape = null;
switch (shapeType)
{
case "Circle":
shape = new Circle(0, 0);
break;
case "Rectangle":
shape = new Rectangle(0, 0);
break;
default:
Console.WriteLine("Unsupported shape type: {0}", shapeType);
break;
}
_shapes[shapeType] = shape;
return shape;
}
}
}
public class Program
{
public static void Main(string[] args)
{
ShapeFactory factory = new ShapeFactory();
Shape circle = factory.GetShape("Circle");
circle.Draw();
}
}
二、java享元模式
享元模式通常通过以下方式实现:
import java.util.HashMap;
import java.util.Map;
// 抽象享元类
abstract class AbstractFlyweight {
protected int color;
protected int size;
// 外部传入的颜色和大小值
public void set(int color, int size) {
this.color = color;
this.size = size;
}
// 内部方法,用于展示对象的状态
public void display() {
System.out.println("Color: " + color + ", Size: " + size);
}
}
// 具体享元类1
class ConcreteFlyweight1 extends AbstractFlyweight {
public ConcreteFlyweight1(int color, int size) {
set(color, size);
}
}
// 具体享元类2
class ConcreteFlyweight2 extends AbstractFlyweight {
public ConcreteFlyweight2(int color, int size) {
set(color, size);
}
}
// 享元工厂类
class FlyweightFactory {
private Map<String, AbstractFlyweight> flyweights;
public FlyweightFactory() {
this.flyweights = new HashMap<>();
}
public AbstractFlyweight getFlyweight(String key) {
if (flyweights.containsKey(key)) {
return flyweights.get(key);
} else {
ConcreteFlyweight1 concreteFlyweight1 = new ConcreteFlyweight1(0, 0); // default values for testing purpose only. 0,0 would not be a valid values in real scenarios.
flyweights.put(key, concreteFlyweight1);
return concreteFlyweight1;
}
}
}
public class FlyweightPatternDemo {
public static void main(String[] args) {
FlyweightFactory flyweightFactory = new FlyweightFactory();
AbstractFlyweight flyweight1 = flyweightFactory.getFlyweight("Object1"); // for the first time this object is created. It will be shared across multiple requests.
AbstractFlyweight flyweight2 = flyweightFactory.getFlyweight("Object2"); // for the second time this object is not created again. It will be retrieved from the flyweights map.
flyweight1.display();
flyweight2.display();
}
}
三、javascript享元模式
在JavaScript中,享元实现方式如下:
// 抽象享元类
class AbstractFlyweight {
constructor(color, size) {
this.color = color;
this.size = size;
}
display() {
console.log(`Color: ${this.color}, Size: ${this.size}`);
}
}
// 具体享元类1
class ConcreteFlyweight1 extends AbstractFlyweight {
constructor(color, size, additionalInfo) {
super(color, size);
this.additionalInfo = additionalInfo;
}
display() {
super.display();
console.log(`Additional Info: ${this.additionalInfo}`);
}
}
// 具体享元类2
class ConcreteFlyweight2 extends AbstractFlyweight {
constructor(color, size, additionalInfo) {
super(color, size);
this.additionalInfo = additionalInfo;
}
display() {
super.display();
console.log(`Additional Info: ${this.additionalInfo}`);
}
}
// 享元工厂类
class FlyweightFactory {
constructor() {
this.flyweights = new Map(); // 使用 Map 存储享元对象,方便查找和管理
}
getFlyweight(key) {
if (this.flyweights.has(key)) {
return this.flyweights.get(key); // 如果已经存在,直接返回已有的享元对象
} else {
const flyweight = new ConcreteFlyweight1(0, 0, 'New Flyweight'); // 默认创建一个新的享元对象,0,0 和 New Flyweight 是示例值,实际使用时需要替换为真实值或随机值等
this.flyweights.set(key, flyweight); // 将新创建的享元对象存储到 Map 中,以便后续重复使用
return flyweight; // 返回新创建的享元对象给调用方使用
}
}
}
四、C++享元模式
以下是在C++中实现享元模式:
#include <iostream>
#include <map>
// 抽象享元类
class AbstractFlyweight {
public:
virtual void operation() = 0;
};
// 具体享元类1
class ConcreteFlyweight1 : public AbstractFlyweight {
public:
void operation() override {
std::cout << "ConcreteFlyweight1 operation" << std::endl;
}
};
// 具体享元类2
class ConcreteFlyweight2 : public AbstractFlyweight {
public:
void operation() override {
std::cout << "ConcreteFlyweight2 operation" << std::endl;
}
};
// 享元工厂类
class FlyweightFactory {
private:
std::map<int, AbstractFlyweight*> flyweights; // 使用 map 存储享元对象,方便查找和管理
public:
AbstractFlyweight* getFlyweight(int key) {
if (flyweights.count(key) > 0) { // 如果已经存在,直接返回已有的享元对象
return flyweights[key];
} else { // 否则,创建一个新的享元对象,并将其存储到 map 中
AbstractFlyweight* flyweight = new ConcreteFlyweight1(); // 默认创建一个 ConcreteFlyweight1 对象作为享元对象,也可以根据需要创建 ConcreteFlyweight2 对象或其他对象作为享元对象
flyweights[key] = flyweight; // 将新创建的享元对象存储到 map 中,以便后续重复使用
return flyweight; // 返回新创建的享元对象给调用方使用
}
}
};
int main() {
FlyweightFactory factory; // 创建享元工厂对象
AbstractFlyweight* flyweight1 = factory.getFlyweight(1); // 从工厂中获取一个享元对象,可以是 ConcreteFlyweight1 或 ConcreteFlyweight2 等其他对象,这里假设是 ConcreteFlyweight1 对象,并将其指针保存到 flyweight1 中
flyweight1->operation(); // 调用享元对象的 operation 方法,输出 "ConcreteFlyweight1 operation" 到控制台中
AbstractFlyweight* flyweight2 = factory.getFlyweight(2); // 从工厂中获取另一个享元对象,同样可以是 ConcreteFlyweight1 或 ConcreteFlyweight2 等其他对象,这里假设是 ConcreteFlyweight2 对象,并将其指针保存到 flyweight2 中
flyweight2->operation(); // 调用享元对象的 operation 方法,输出 "ConcreteFlyweight2 operation" 到控制台中,由于 flyweight2 是新创建的 ConcreteFlyweight2 对象,因此输出结果与之前的 flyweight1 不相同
return 0;
}
五、python享元模式
以下是在python中实现享元模式:
from abc import ABC, abstractmethod
# 享元类
class Flyweight(ABC):
@abstractmethod
def operation(self):
pass
# 具体享元类1
class ConcreteFlyweight1(Flyweight):
def operation(self):
super().operation()
print("ConcreteFlyweight1 operation")
# 具体享元类2
class ConcreteFlyweight2(Flyweight):
def operation(self):
super().operation()
print("ConcreteFlyweight2 operation")
# 享元工厂类
class FlyweightFactory:
_flyweights = {}
def get_flyweight(self, key):
if key in self._flyweights:
return self._flyweights[key]
else:
flyweight = ConcreteFlyweight1() # 或者 ConcreteFlyweight2 等其他具体享元类
self._flyweights[key] = flyweight
return flyweight
def put_flyweight(self, key, flyweight):
self._flyweights[key] = flyweight
#使用示例:
factory = FlyweightFactory()
flyweight1 = factory.get_flyweight(1) # 返回一个 ConcreteFlyweight1 对象,key 为 1 的对象已经存在则直接返回,否则创建一个新的对象并存储到字典中
flyweight2 = factory.get_flyweight(2) # 返回一个 ConcreteFlyweight1 对象,key 为 2 的对象已经存在则直接返回,否则创建一个新的对象并存储到字典中
flyweight1.operation() # 输出 "ConcreteFlyweight1 operation"
flyweight2.operation() # 输出 "ConcreteFlyweight1 operation"
六、go享元模式
以下是一个示例,展示了如何在go中实现享元模式:
package main
import (
"fmt"
)
// Flyweight 接口定义了享元对象的行为
type Flyweight interface {
Operation()
}
// ConcreteFlyweight1 和 ConcreteFlyweight2 是具体的享元对象
type ConcreteFlyweight1 struct {
// 共享状态
state1 string
}
func (f *ConcreteFlyweight1) Operation() {
fmt.Println("ConcreteFlyweight1 operation with state1:", f.state1)
}
type ConcreteFlyweight2 struct {
// 共享状态
state2 int
}
func (f *ConcreteFlyweight2) Operation() {
fmt.Println("ConcreteFlyweight2 operation with state2:", f.state2)
}
// FlyweightFactory 是享元工厂,用于创建和管理享元对象
type FlyweightFactory struct {
flyweights map[string]Flyweight
}
func NewFlyweightFactory() *FlyweightFactory {
return &FlyweightFactory{
flyweights: make(map[string]Flyweight),
}
}
func (f *FlyweightFactory) GetFlyweight(key string) Flyweight {
if flyweight, ok := f.flyweights[key]; ok {
return flyweight // 如果已存在,则直接返回已有的享元对象
} else {
// 如果不存在,则创建一个新的享元对象,并将其存储到 flyweights 中
switch key {
case "state1":
flyweight := &ConcreteFlyweight1{state1: "shared state 1"}
f.flyweights[key] = flyweight
return flyweight
case "state2":
flyweight := &ConcreteFlyweight2{state2: 42}
f.flyweights[key] = flyweight
return flyweight
default:
return nil
}
}
}
func main() {
factory := NewFlyweightFactory() // 创建享元工厂对象
flyweight1 := factory.GetFlyweight("state1") // 从工厂中获取一个享元对象,这里使用 key 为 "state1" 的 ConcreteFlyweight1 对象作为示例,并将其指针保存到 flyweight1 中
flyweight1.Operation() // 调用享元对象的 Operation 方法,输出 "ConcreteFlyweight1 operation with state1: shared state 1" 到控制台中
flyweight2 := factory.GetFlyweight("state2") // 从工厂中获取另一个享元对象,这里使用 key 为 "state2" 的 ConcreteFlyweight2 对象作为示例,并将其指针保存到 flyweight2 中
}
七、PHP享元模式
以下是一个示例,展示了如何在PHP中实现享元模式:
<?php
// 享元接口
interface Flyweight {
public function operation();
}
// 具体享元类1
class ConcreteFlyweight1 implements Flyweight {
private $state1;
public function operation() {
// 具体操作
$this->state1 = "shared state 1";
echo "ConcreteFlyweight1 operation with state1: " . $this->state1 . "\n";
}
}
// 具体享元类2
class ConcreteFlyweight2 implements Flyweight {
private $state2;
public function operation() {
// 具体操作
$this->state2 = 42;
echo "ConcreteFlyweight2 operation with state2: " . $this->state2 . "\n";
}
}
// 享元工厂类
class FlyweightFactory {
private $flyweights;
public function __construct() {
$this->flyweights = [];
}
public function getFlyweight($key) {
if (isset($this->flyweights[$key])) {
return $this->flyweights[$key]; // 如果已存在,则直接返回已有的享元对象
} else {
// 如果不存在,则创建一个新的享元对象,并将其存储到 flyweights 中
switch ($key) {
case "state1":
$flyweight = new ConcreteFlyweight1();
$this->flyweights["state1"] = $flyweight;
return $flyweight;
case "state2":
$flyweight = new ConcreteFlyweight2();
$this->flyweights["state2"] = $flyweight;
return $flyweight;
default:
return null;
}
}
}
}
// 使用享元模式示例
$factory = new FlyweightFactory(); // 创建享元工厂对象
$flyweight1 = $factory->getFlyweight("state1"); // 从工厂中获取一个享元对象,这里使用 key 为 "state1" 的 ConcreteFlyweight1 对象作为示例,并将其指针保存到 $flyweight1 中
$flyweight1->operation(); // 调用享元对象的 Operation 方法,输出 "ConcreteFlyweight1 operation with state1: shared state 1" 到控制台中
$flyweight2 = $factory->getFlyweight("state2"); // 从工厂中获取另一个享元对象,这里使用 key 为 "state2" 的 ConcreteFlyweight2 对象作为示例,并将其指针保存到 $flyweight2 中
$flyweight2->operation(); // 调用享元对象的 Operation 方法,输出 "ConcreteFlyweight2 operation with state2: 42" 到控制台中
?>
《完结》
上一篇《原型模式》 下一篇《责任链模式》