本文所有案例代码
码云:https://gitee.com/helloworld6379/designPattern
Github:Github地址
设计模式概述
1 设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通
用解决方案,设计模式(Design pattern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
2 设计模式的本质提高 软件的维护性,通用性和扩展性,并降低软件的复杂度。
3 设计模式并不局限于某种语言,java,php,c++ 都有设计模式.
设计模式类型
设计模式分为三种类型,共 23 种
1 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
2 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。
简单介绍
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
意图:运用共享技术有效地支持大量细粒度的对象。
主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。
如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。
关键代码:用 HashMap 存储这些对象。
应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。
优点:大大减少对象的创建,降低系统的内存,使效率提高。
缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。
注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。
享元模式的原理类图
说明
- FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口 或实现
- ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
- UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
- FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法
内部状态和外部状态
比如围棋、五子棋、跳棋,它们都有大量的棋子对象,围棋和五子棋只有黑白两色,跳棋颜色多一点,所以棋子颜 色就是棋子的内部状态;而各个棋子之间的差别就是位置的不同,当我们落子后,落子颜色是定的,但位置是变化 的,所以棋子坐标就是棋子的外部状态。
- 享元模式提出了两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态了,即将对象的信息分为两 个部分:内部状态和外部状态
- 内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变
- 外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
- 举个例子:围棋理论上有 361 个空位可以放棋子,每盘棋都有可能有两三百个棋子对象产生,因为内存空间有 限,一台服务器很难支持更多的玩家玩围棋游戏,如果用享元模式来处理棋子,那么棋子对象就可以减少到只 有两个实例,这样就很好的解决了对象的开销问题
实现
/**
* @Description 电脑接口
* @Author: LiuXing
* @Date: 2020/5/28 21:32
*/
public interface Computer {
void showInfo();
}
/**
* @Description 具体的电脑实体类
* @Author: LiuXing
* @Date: 2020/5/28 21:32
*/
public class HaseeComputer implements Computer {
private String size;
private String cpu;
private String ssd;
private String ram;
public HaseeComputer(String size){
this.size = size;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setSsd(String ssd) {
this.ssd = ssd;
}
public void setRam(String ram) {
this.ram = ram;
}
@Override
public void showInfo() {
System.out.println("HaseeComputer{" +
"size='" + size + '\'' +
", cpu='" + cpu + '\'' +
", ssd='" + ssd + '\'' +
", ram='" + ram + '\'' +
'}');
}
}
/**
* @Description 电脑工厂
* @Author: LiuXing
* @Date: 2020/5/28 21:32
*/
public class ComputerFactory {
private static final HashMap<String,Computer> computerMap = new HashMap<>();
public static Computer getComputer(String size){
HaseeComputer computer = (HaseeComputer)computerMap.get(size);
if (computer == null){
computer = new HaseeComputer(size);
computerMap.put(size,computer);
System.out.println("造了一个 "+ size + "的笔记本");
}
return computer;
}
}
/**
* @Description 享元模式测试
* @Author: LiuXing
* @Date: 2020/5/28 21:32
*/
public class FlyweightTest {
private static final String sizes[] = {"13寸","14寸","15寸","17寸"};
private static final String cpus[] = {"i3","i5","i7","i9"};
private static final String rams[] = {"4G","8G","16G","32G"};
private static final String ssds[] = {"250G","500G","1T","2T"};
public static void main(String[] args) {
for (int i = 0; i < 200; i++){
HaseeComputer hasee = (HaseeComputer) ComputerFactory.getComputer(getSize());
hasee.setCpu(getCpu());
hasee.setRam(getRam());
hasee.setSsd(getSSD());
hasee.showInfo();
}
}
private static String getSize(){
return sizes[(int)(Math.random()*sizes.length)];
}
private static String getCpu(){
return cpus[(int)(Math.random()*cpus.length)];
}
private static String getRam(){
return rams[(int)(Math.random()*rams.length)];
}
private static String getSSD(){
return ssds[(int)(Math.random()*ssds.length)];
}
}
享元模式在 JDK中 的应用
JDK中Integer的valueOf方法就用到了享元模式
/**
* @Description 享元模式下JDK中的应用
* @Author LiuXing
* @Date 2020/06/06 19:28
*/
public class JDKTest {
public static void main(String[] args) {
Integer x = Integer.valueOf(127);
Integer y = new Integer(127);
Integer z = Integer.valueOf(127);
Integer n = new Integer(127);
System.out.println(x == y);
System.out.println(x == z);
System.out.println(n == x);
System.out.println(n == y);
///如果 Integer.valueOf(x) x 在 -128 --- 127 直接,就是使用享元模式返回,如果不在范围内,就new一个
//在 valueOf 方法中,先判断值是否在 IntegerCache 中,如果不在,就创建新的 Integer(new), 否则,就直接从缓存池返回
Integer xx = Integer.valueOf(128);
Integer yy = Integer.valueOf(128);
System.out.println(xx == yy);
}
}
false
true
false
false
false