设计模式:享元模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《原型模式》                                                                      下一篇《责任链模式》

简介:

享元模式,它是一种结构型设计模式,旨在有效地支持大量细粒度的对象共享,通过共享对象来减少内存消耗和提高性能。享元模式将对象的状态分为内部状态和外部状态。内部状态是对象的固定部分,可以在多个对象之间共享,而外部状态是对象的变化部分,需要在使用时传递给对象。享元模式将内部状态存储在享元对象中,并将外部状态作为参数传递给方法。

享元模式包含以下几个关键组件:
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" 到控制台中  
?>

《完结》

上一篇《原型模式》                                                                     下一篇《责任链模式》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值