当前位置:首页 > 编程笔记 > 正文
已解决

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

来自网友在路上 157857提问 提问时间:2023-10-30 02:17:40阅读次数: 57

最佳答案 问答题库578位专家为你答疑解惑

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

简介:

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

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

《完结》

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

查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"设计模式:享元模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)":http://eshow365.cn/6-27545-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!