设计模式

  • 工厂模式

  1. 创建一个接口;
    public interface Shape {
       void draw();
    }
  2. 创建实现接口的实体类;
    public class Rectangle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
  3. 创建一个工厂,生成基于给定信息的实体类的对象;
    public class ShapeFactory {
       //使用 getShape 方法获取形状类型的对象
       public Shape getShape(String shapeType){
          if(shapeType == null){
             return null;
          }        
          if(shapeType.equalsIgnoreCase("CIRCLE")){
             return new Circle();//无参构造
          } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
             return new Rectangle();
          } else if(shapeType.equalsIgnoreCase("SQUARE")){
             return new Square();
          }
          return null;
       }
    }
  4. 使用该工厂,通过传递类型信息来获取实体类的对象;
    public class FactoryPatternDemo {
     
       public static void main(String[] args) {
          ShapeFactory shapeFactory = new ShapeFactory();
     
          //获取 Circle 的对象,并调用它的 draw 方法
          Shape shape1 = shapeFactory.getShape("CIRCLE");
     
          //调用 Circle 的 draw 方法
          shape1.draw();
     
          //获取 Rectangle 的对象,并调用它的 draw 方法
          Shape shape2 = shapeFactory.getShape("RECTANGLE");
     
          //调用 Rectangle 的 draw 方法
          shape2.draw();
     
          //获取 Square 的对象,并调用它的 draw 方法
          Shape shape3 = shapeFactory.getShape("SQUARE");
     
          //调用 Square 的 draw 方法
          shape3.draw();
       }
    }

     

  • 抽象工厂

  1. 超级工厂创建其他工厂;
  2. 与工厂模式不同的是给工厂再创建一个工厂;
    public abstract class AbstractFactory {
       public abstract Color getColor(String color);
       public abstract Shape getShape(String shape);
    }
  3. 创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
    public class ShapeFactory extends AbstractFactory {
        
       @Override
       public Shape getShape(String shapeType){
          if(shapeType == null){
             return null;
          }        
          if(shapeType.equalsIgnoreCase("CIRCLE")){
             return new Circle();
          } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
             return new Rectangle();
          } else if(shapeType.equalsIgnoreCase("SQUARE")){
             return new Square();
          }
          return null;
       }
       
       @Override
       public Color getColor(String color) {
          return null;
       }
    }
  4. 创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
    public class FactoryProducer {
       public static AbstractFactory getFactory(String choice){
          if(choice.equalsIgnoreCase("SHAPE")){
             return new ShapeFactory();
          } else if(choice.equalsIgnoreCase("COLOR")){
             return new ColorFactory();
          }
          return null;
       }
    }
  5. 使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
    public class AbstractFactoryPatternDemo {
       public static void main(String[] args) {
     
          //获取形状工厂
          AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
     
          //获取形状为 Circle 的对象
          Shape shape1 = shapeFactory.getShape("CIRCLE");
     
          //调用 Circle 的 draw 方法
          shape1.draw();
     
          //获取形状为 Rectangle 的对象
          Shape shape2 = shapeFactory.getShape("RECTANGLE");
     
          //调用 Rectangle 的 draw 方法
          shape2.draw();
          
          //获取形状为 Square 的对象
          Shape shape3 = shapeFactory.getShape("SQUARE");
     
          //调用 Square 的 draw 方法
          shape3.draw();
     
          //获取颜色工厂
          AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
     
          //获取颜色为 Red 的对象
          Color color1 = colorFactory.getColor("RED");
     
          //调用 Red 的 fill 方法
          color1.fill();
     
          //获取颜色为 Green 的对象
          Color color2 = colorFactory.getColor("GREEN");
     
          //调用 Green 的 fill 方法
          color2.fill();
     
          //获取颜色为 Blue 的对象
          Color color3 = colorFactory.getColor("BLUE");
     
          //调用 Blue 的 fill 方法
          color3.fill();
       }
    }
  • 单例模式
  1. 一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不要实例化该类的对象;
  2. 私有化静态变量;
    private static Singleton instance;
  3. 私有化构造方法;
    private SingleObject(){}
  4. 定义一个方法来为客户端提供类实例;
  • 懒汉式
  1. 类加载不会导致该单实例对象被创建,而是首次使用该对象时才会被创建;
  2. 不安全的
    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
      
        public static Singleton getInstance() {  
            if (instance == null) {  //如果instance为null说明没有实例化过,保证创建的对象唯一
                instance = new Singleton();  
            }  
            return instance;  
        }  
    }
  3. 安全的(区别就是加了synchronized)
    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
        public static synchronized Singleton getInstance() {  
            if (instance == null) {  
                instance = new Singleton();  
            }  
            return instance;  
        }  
    }
  • 饿汉式
  1. 枚举饿汉式:防止反射、实例化破坏单例,unsafe还是能破坏单例;
    public enum Singleton {  
        INSTANCE;  
        public void whateverMethod() {  
        }  
    }
  2. 类加载就会导致该单实例对象被创建;
    public class Singleton {  
        private static Singleton instance = new Singleton();  //
        private Singleton (){}  
        public static Singleton getInstance() {  
        return instance;  
        }  
    }
  • 双检索模式(懒汉式优化)
  1. 和前两个的区别是用可见方法volatile,用了双重检查机制
    public class Singleton {  
        private volatile static Singleton singleton;  //volatile保证变量的可见性
        private Singleton (){}  
        public static Singleton getSingleton() {  
        if (singleton == null) {  //先检查实例是否存在,如果不存在才进入下面的代码块
            synchronized (Singleton.class) {  
                if (singleton == null) {  //同步代码块。线程安全的创建实例
                    singleton = new Singleton(); //再次检查实例是否存在,如果不存在才算真正创建实例 
                }  
            }  
        }  
        return singleton;  
        }  
    }

     

  • 原型模式

     

  1. 原型模式和克隆有关系,所以要首先实现cloneable接口;(浅克隆)
    1. 创建一个实现了 Cloneable 接口的原型类;
    2. 在测试类中,先实例化一个原型类,其他的克隆这个原型类

    • 深克隆
    1. 深克隆是指把奖状类的学生类也克隆,开辟一个新的内存;
      public Object clone() throws CloneNotSupportedException {
              FreightStation ft=(FreightStation)super.clone();//把object类型强制转换
              Truck t=(Truck)truck.clone();//truck是Truck类型的变量
              ft.truck=t;//把t赋格fFreightStation类中的truck
      return ft; }
  2. 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象;
  3. 创建一个实现了 Cloneable 接口的抽象类;
    public abstract class Shape implements Cloneable {
       
       private String id;
       protected String type;
       
       abstract void draw(); //抽象方法,继承本类时需要被重写
       
       public String getType(){
          return type;
       }
       
       public String getId() {
          return id;
       }
       
       public void setId(String id) {
          this.id = id;
       }
       
       public Object clone() {//重写克隆方法
          Object clone = null;
          try {
             clone = super.clone();
          } catch (CloneNotSupportedException e) {
             e.printStackTrace();
          }
          return clone;
       }
    }
  4. 创建扩展了上面抽象类的实体类;
    public class Rectangle extends Shape {
     
       public Rectangle(){
         type = "Rectangle";
       }
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
  5. 创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。
    import java.util.Hashtable;
     
    public class ShapeCache {
        
       private static Hashtable<String, Shape> shapeMap 
          = new Hashtable<String, Shape>();
     
       public static Shape getShape(String shapeId) {
          Shape cachedShape = shapeMap.get(shapeId); 
          return (Shape) cachedShape.clone(); //返回的克隆的对象
       }
     
       // 对每种形状都运行数据库查询,并创建该形状
       // shapeMap.put(shapeKey, shape);
       // 例如,我们要添加三种形状
       public static void loadCache() {
          Circle circle = new Circle();
          circle.setId("1");
          shapeMap.put(circle.getId(),circle);
     
          Square square = new Square();
          square.setId("2");
          shapeMap.put(square.getId(),square);
     
          Rectangle rectangle = new Rectangle();
          rectangle.setId("3");
          shapeMap.put(rectangle.getId(),rectangle);
       }
    }
  6. PrototypePatternDemo 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
    public class PrototypePatternDemo {
       public static void main(String[] args) {
          ShapeCache.loadCache();
     
          Shape clonedShape = (Shape) ShapeCache.getShape("1");
          System.out.println("Shape : " + clonedShape.getType());        
     
          Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
          System.out.println("Shape : " + clonedShape2.getType());        
     
          Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
          System.out.println("Shape : " + clonedShape3.getType());        
       }
    }
  • 代理模式
  1. 由于某些原因需要给某对象提供一个代理以控制该对象的访问,这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象的中介;
  • 静态代理
  1. 静态代理代理类在编译器就生成;
  2. 例子:售卖火车票,代售点,火车站
    1. 写一个买火车票的接口;
    2. 火车站类实现买票接口,重写接口方法;
    3. 代售点实现接口,私有火车站类对象,在重新的售卖接口方法中调用火车站类的售票方法;
    4. 写客户端类,创建代售点类对象,调用代售点卖票方法;
  3. 创建一个接口
    public interface Image {
       void display();
    }
  4. 创建实现接口的实体类;
    public class RealImage implements Image {
     
       private String fileName;
     
       public RealImage(String fileName){
          this.fileName = fileName;
          loadFromDisk(fileName);
       }
     
       @Override
       public void display() {
          System.out.println("Displaying " + fileName);
       }
     
       private void loadFromDisk(String fileName){
          System.out.println("Loading " + fileName);
       }
    }

    代理类实现接口

    public class ProxyImage implements Image{
     
       private RealImage realImage;
       private String fileName;
     
       public ProxyImage(String fileName){
          this.fileName = fileName;
       }
     
       @Override
       public void display() {
          if(realImage == null){
             realImage = new RealImage(fileName);
          }
          realImage.display();
       }
    }
  5. 当被请求时,使用 ProxyImage 来获取 RealImage 类的对象;
    public class ProxyPatternDemo {//客户端类
       
       public static void main(String[] args) {
          Image image = new ProxyImage("test_10mb.jpg");
     
          // 图像将从磁盘加载
          image.display(); 
          System.out.println("");
          // 图像不需要从磁盘加载
          image.display();  
       }
    }
  • 动态代理
  • jdk
  1. 动态代理代理类则是在Java运行时动态生成,是在程序中生成的,不可见,动态代理又有JDK代理和CGLib代理两种;
  2. 与静态代理不同的是多了一个代理工厂,在代理工厂类中创建的工厂对象,就利用反射的.newInstance()方法,这个方法还有三个参数(指定目标对象的字节码文件.类加载器,代理类实现的接口的字节码对象,事件处理器)创建的;实际上调用了invoke方法;

  3. invoke具体方法;

  4. 使用代理工厂来创建代理

  • CGLTB代理
  1. 如果没有定义买票的接口,只定义了火车站类,JDK就无法使用了;
  2. 使用时需要加pom依赖,目标对象不能为final,否则报错。
  3. 底层使用ASM字节码生成框架,使用字节码技术生成代理类;
  • 静态代理和动态代理相比,动态代理最大的好处是在接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(invoke);
  • jdk和cglib区别,如果目标对象没有实现接口就用cglib,有实现接口就用jdk;
posted @ 2024-02-11 16:30  卡皮巴拉  阅读(2)  评论(0编辑  收藏  举报