享元模式是通过共享对象减少内存使用,来提高程序性能。在此模式中,分为内部状态和外部状态,其中相似的对象被存储在享元对象内部,并对于所有享元对象都是相同的,且状态通常是不变的。只在需要时内部共享,而不是每次创建新的对象。而外部状态是享元对象依赖的,可能变化的部分。这部分状态不存储在享元对象内部,而是在使用享元对象时传递给对象。
在棋类游戏中,棋子可以看作是享元对象,因为棋子与棋子之间有着相同的属性和方法,例如在颜色、大小、移动规则上都有着相同的特质。因此在棋类游戏中,可以使用享元模式来共享相同的棋子对象,避免创建大量的棋子对象,从而提高游戏性能。
package com.technologystatck.designpattern.mode.flyweight; import java.util.HashMap; import java.util.Map; public class Flyweight { public static void main(String[] args) { //实例化享元工厂对象 FlyweightFactory factory = new FlyweightFactory(); //获取或创建享元对象,并传递外部状态 Flyweights flyweightA = factory.getFlyweight("A"); flyweightA.operation("External State A"); Flyweights flyweightB = factory.getFlyweight("B"); flyweightB.operation("External State B"); Flyweights flyweightC = factory.getFlyweight("A"); flyweightC.operation("External State C"); } } //创建享元接口 interface Flyweights { //操作外部状态 void operation(String extrinsicState); } //实现具体享元类,存储内部状态 class ConcreteFlyweight implements Flyweights{ //内部状态 private String intrinsicState; public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } @Override public void operation(String extrinsicState) { System.out.println("Intrinsic State: "+intrinsicState+",External State: "+extrinsicState); } } //创建享元工厂类,创建并管理Flyweight对象, //当用户请求一个Flyweight时,享元工厂会提供一个已经创建的实例或创建一个 class FlyweightFactory{ private Mapflyweights=new HashMap<>(); public Flyweights getFlyweight(String key){ //若没有享元对象时,就将传进来的key值创建一个 if(!flyweights.containsKey(key)){ flyweights.put(key,new ConcreteFlyweight(key)); } return flyweights.get(key); } }
在一个图形编辑器中,用户可以绘制不同类型的图形,包括圆形(CIRCLE)、矩形(RECTANGLE)、三角形(TRIANGLE)等。现在,请你实现一个图形绘制程序,要求能够共享相同类型的图形对象,以减少内存占用。
输入包含多行,每行表示一个绘制命令。每个命令包括两部分:
图形类型(Circle、Rectangle 或 Triangle)
绘制的坐标位置(两个整数,分别表示 x 和 y)
对于每个绘制命令,输出相应图形被绘制的位置信息。如果图形是首次绘制,输出 “drawn at”,否则输出 “shared at”。
package com.technologystatck.designpattern.mode.flyweight; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); //创建工厂实例 GraphicFactory graphicFactory = new GraphicFactory(); while(scanner.hasNext()){ String command = scanner.nextLine(); //定义一个静态方法 proessCommand(graphicFactory,command); } } public static void proessCommand(GraphicFactory graphicFactory,String command){ //定义数组存放类型变量 String[] parts = command.split(" "); DrawType drawType=DrawType.valueOf(parts[0]); int x=Integer.parseInt(parts[1]); int y=Integer.parseInt(parts[2]); // Graphic graphic=graphicFactory.getGraphic(drawType); graphic.draw(new ConcretePosition(x,y)); ((ConcreteGraphic) graphic).setFirstTime(false); } } //使用枚举创建图形类型 enum DrawType{ CIRCLE,RECTANGLE,TRIANGLE; } //创建坐标类 class ConcretePosition{ //内部状态 private int x; private int y; public ConcretePosition() { } public ConcretePosition(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } //创建图像享元接口 interface Graphic{ //外部状态 void draw(ConcretePosition concretePosition); } //创建具体图形实现类 class ConcreteGraphic implements Graphic{ //内部状态 private DrawType drawType; public ConcreteGraphic(DrawType drawType) { this.drawType = drawType; } //检查是否是第一次绘制该图形 private Boolean isFirstTime=true; public Boolean getFirstTime() { return isFirstTime; } public void setFirstTime(Boolean firstTime) { isFirstTime = firstTime; } //描绘图形方法 @Override public void draw(ConcretePosition concretePosition) { System.out.println(drawType+(isFirstTime ? "drawn":"shared")+" at ("+ concretePosition.getX()+" , "+concretePosition.getY()+")"); } } //创建享元图形工厂 class GraphicFactory{ private MapgraphicEditors=new HashMap<>(); //检查是否已创建对象 public Graphic getGraphic(DrawType drawType){ //若时第一次创建,就实例化一个新对象,否则就返回已经创建的对象。 if(!graphicEditors.containsKey(drawType)){ graphicEditors.put(drawType,new ConcreteGraphic(drawType)); } return graphicEditors.get(drawType); } }