设计模式:享元模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
最佳答案 问答题库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 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!