设计模式之桥接模式、组合模式与享元模式

目录

桥接模式

简介

优缺点

结构

实现

运用场景

组合模式

简介

优缺点

结构

实现

运用场景

享元模式

简介

优缺点

结构

实现

运用场景


桥接模式

简介

将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度

优缺点

优点:

1.抽象与现实分离,扩展能力强

2.符合开闭原则、合成复用原则

3.实现细节透明

缺点:

由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度

结构

可以将抽象化部分与实现化部分分开,取消二者的继承关系,改用组合关系

角色:

抽象化角色:定义抽象类,并包含一个对实现化对象的应用

扩展抽象化角色:抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法

实现化角色:定义实现化角色的接口,供扩展抽象化角色调用

具体实现化角色:给出实现化角色接口的具体实现

实现

java 复制代码
package bridge;
public class BridgeTest {
    public static void main(String[] args) {
        Implementor imple = new ConcreteImplementorA();
        Abstraction abs = new RefinedAbstraction(imple);
        abs.Operation();
    }
}
//实现化角色
interface Implementor {
    public void OperationImpl();
}
//具体实现化角色
class ConcreteImplementorA implements Implementor {
    public void OperationImpl() {
        System.out.println("具体实现化(Concrete Implementor)角色被访问");
    }
}
//抽象化角色
abstract class Abstraction {
    protected Implementor imple;
    protected Abstraction(Implementor imple) {
        this.imple = imple;
    }
    public abstract void Operation();
}
//扩展抽象化角色
class RefinedAbstraction extends Abstraction {
    protected RefinedAbstraction(Implementor imple) {
        super(imple);
    }
    public void Operation() {
        System.out.println("扩展抽象化(Refined Abstraction)角色被访问");
        imple.OperationImpl();
    }
}
​

运用场景

当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。

当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。

当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时

组合模式

简介

运用了树形结构,该模式的核心思想是:将多个对象组合成树形结构,以此结构来表示"整体-部分"之间的层次关系

优缺点

优点:

1.使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码

2.更容易在组合体内加入新的对象

缺点:

设计较复杂,客户端需要花更多时间理清类之间的层次关系;

不容易限制容器中的构件;

不容易用继承的方法来增加构件的新功能

结构

角色:

抽象构件角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为

树叶构件角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件

树枝构件角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件

实现

java 复制代码
public class CompositePattern {
    public static void main(String[] args) {
        Component c0 = new Composite();
        Component c1 = new Composite();
        Component leaf1 = new Leaf("1");
        Component leaf2 = new Leaf("2");
        Component leaf3 = new Leaf("3");
        c0.add(leaf1);
        c0.add(c1);
        c1.add(leaf2);
        c1.add(leaf3);
        c0.operation();
    }
}
//抽象构件
interface Component {
    public void add(Component c);
    public void remove(Component c);
    public Component getChild(int i);
    public void operation();
}
//树叶构件
class Leaf implements Component {
    private String name;
    public Leaf(String name) {
        this.name = name;
    }
    public void add(Component c) {
    }
    public void remove(Component c) {
    }
    public Component getChild(int i) {
        return null;
    }
    public void operation() {
        System.out.println("树叶" + name + ":被访问!");
    }
}
//树枝构件
class Composite implements Component {
    private ArrayList<Component> children = new ArrayList<Component>();
    public void add(Component c) {
        children.add(c);
    }
    public void remove(Component c) {
        children.remove(c);
    }
    public Component getChild(int i) {
        return children.get(i);
    }
    public void operation() {
        for (Object obj : children) {
            ((Component) obj).operation();
        }
    }
}

运用场景

在需要表示一个对象整体与部分的层次结构的场合

要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合

享元模式

简介

用于减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的方式;尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

优缺点

优点:

减少内存使用:由于享元模式共享对象,因此可以减少内存使用。

提高性能:创建和销毁对象会占用大量的CPU时间和内存空间。因此,使用享元模式可以提高性能。

代码简洁:享元模式可以使代码更简洁,因为该模式使用相同的对象来处理多个请求,而不需要创建大量的对象。

缺点:

共享对象可能会对线程安全造成问题。如果不正确地实现共享机制,则可能导致多个线程对同一对象进行更改,从而导致竞争条件。

需要牺牲一定的时间和空间,来实现对象共享和控制机制。这意味着,当对象之间没有重复性时,使用享元模式可能会导致额外的开销

结构

角色:

抽象享元角色:通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公 共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法 来设置外部数据(外部状态)。

具体享元角色 :它实现了抽象享元类,称为享元对象;在具体享元 类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享 元类提供唯一的享元对象。

非享元角色 :并不是所有的抽象享元类的子类都需要被共享,不 能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

享元工厂角色 :负责创建和管理享元角色。当客户对象请求一个享元 对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在 的话,则创建一个新的享元对象

实现

java 复制代码
1.创建一个接口

public interface Shape {
   void draw();
}

2.创建实现接口的实体类

public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;
 
   public Circle(String color){
      this.color = color;     
   }
 
   public void setX(int x) {
      this.x = x;
   }
 
   public void setY(int y) {
      this.y = y;
   }
 
   public void setRadius(int radius) {
      this.radius = radius;
   }
 
   @Override
   public void draw() {
      System.out.println("Circle: Draw() [Color : " + color 
         +", x : " + x +", y :" + y +", radius :" + radius);
   }
}

3.创建一个工厂,生成基于给定信息的实体类的对象

import java.util.HashMap;
 
public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap<>();
 
   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);
 
      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}

4.使用该工厂,通过传递颜色信息来获取实体类的对象

public class FlyweightPatternDemo {
   private static final String colors[] = 
      { "Red", "Green", "Blue", "White", "Black" };
   public static void main(String[] args) {
 
      for(int i=0; i < 20; ++i) {
         Circle circle = 
            (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }
   private static String getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   private static int getRandomX() {
      return (int)(Math.random()*100 );
   }
   private static int getRandomY() {
      return (int)(Math.random()*100);
   }
}

运用场景

当需要创建大量相似对象时可以使用享元模式,例如游戏中的道具、棋子等。

当对象需要被共享时,可以使用享元模式,例如线程池中的线程。

当系统的内存资源相对有限时可以考虑使用享元模式,以减少内存的使用。

当需要减少对象的创建次数、降低系统开销时可以使用享元模式。

相关推荐
考虑考虑6 小时前
点阵图更改背景文字
java·后端·java ee
ZHE|张恒7 小时前
Spring Boot 3 + Flyway 全流程教程
java·spring boot·后端
TDengine (老段)7 小时前
TDengine 数学函数 CRC32 用户手册
java·大数据·数据库·sql·时序数据库·tdengine·1024程序员节
心随雨下7 小时前
Tomcat日志配置与优化指南
java·服务器·tomcat
Kapaseker7 小时前
Java 25 中值得关注的新特性
java
wljt7 小时前
Linux 常用命令速查手册(Java开发版)
java·linux·python
撩得Android一次心动8 小时前
Android 四大组件——BroadcastReceiver(广播)
android·java·android 四大组件
canonical_entropy8 小时前
Nop平台到底有什么独特之处,它能用在什么场景?
java·后端·领域驱动设计
chilavert3188 小时前
技术演进中的开发沉思-174 java-EJB:分布式通信
java·分布式
不是株8 小时前
JavaWeb(后端进阶)
java·开发语言·后端