美文网首页
设计模式概要(一)

设计模式概要(一)

作者: 放下梧菲 | 来源:发表于2020-05-21 22:16 被阅读0次

    设计模式是软件开发人员在开发过程中面临一般问题的解决方案,我们用的java库中,尤其是J2EE中,有大量设计模式构成的代码。如果你不懂设计模式,你甚至不能看懂框架的底层实现,而掌握了设计模式,对于理解框架,对于以后自己产品的设计,大有好处。

    设计模式一共有23种,这些模式可以分为三大类,创建型,结构型,行为型,我们学习设计模式要抓住每个模式的特征,以及模式与模式的区别联系,这样学起来事半功倍,因此我的学习也是从三大类着手开始进行。

    1、创建型设计模式

    1、工厂模式

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
    在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

    介绍

    意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

    主要解决:主要解决接口选择的问题。

    何时使用:我们明确地计划不同条件下创建不同实例时。

    如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

    关键代码:创建过程在其子类执行。

    应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

    优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

    缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

    使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

    注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

    实现

    我们将创建一个 Shape 接口和实现 Shape 接口的实体类。下一步是定义工厂类 ShapeFactory

    FactoryPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。

    工厂模式的 UML 图

    例子:
    步骤 1
    创建一个接口:

    Shape.java
    public interface Shape {
       void draw();
    }
    

    步骤 2
    创建实现接口的实体类。

    Rectangle.java
    public class Rectangle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
    Square.java
    public class Square implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Square::draw() method.");
       }
    }
    Circle.java
    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    

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

    ShapeFactory.java
    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();
       
    }
    

    如何真正理解工厂模式呢?我认为关键就在于理清我们为什么需要工厂。
    我们来看shapeFactory究竟做了什么事?它其实就是根据你传入的参数,做了不同的事,这里的事其实就是创建了构建了不同的对象,这个对象不需要我们自己去手动new,在工厂里的方法会帮我们完成这件事。
    那对我们有什么好处呢?首先我们不需要自己去创建不同的类了,我们只需要调用一个方法,就可以通过整个方法创建不用的类,我们不需要知道这个类该如何创建,我们只需要传递进去固定的参数即可。那无疑是简便了我们的操作。
    范例中的方法还是比较简单的,如果创建一个对象变得复杂,那工厂方法就更加有存在的必要了。
    还有一个好处就是,能够帮助我们是使用者,更快更准的定位接口的实现类。
    但是工厂模式也是有缺点的,我们可以看得出来,这个模式下整个系统会变得复杂起来,当我们要增加一个shape,我们需要做什么?我们需要增加一个shape的实现,这是毋庸置疑的,我们还需要在工厂里增加我们的实现,也就是说代码量会提升,但其实这并不能算是严格的缺点,只能说是有些情况下我们不需要使用工厂方法,当创建一些简单对象的时候,我们并不需要额外增加一个工厂类来增加代码量。

    2、抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

    介绍

    意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

    主要解决:主要解决接口选择的问题。

    何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

    如何解决:在一个产品族里面,定义多个产品。

    关键代码:在一个工厂里聚合多个同类产品。

    应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

    优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

    缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

    使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

    注意事项:产品族难扩展,产品等级易扩展。

    实现

    我们将创建 ShapeColor 接口和实现这些接口的实体类。下一步是创建抽象工厂类 AbstractFactory。接着定义工厂类 ShapeFactoryColorFactory,这两个工厂类都是扩展了 AbstractFactory。然后创建一个工厂创造器/生成器类 FactoryProducer

    AbstractFactoryPatternDemo,我们的演示类使用 FactoryProducer 来获取 AbstractFactory 对象。它将向 AbstractFactory 传递形状信息 ShapeCIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。同时它还向 AbstractFactory 传递颜色信息 ColorRED / GREEN / BLUE),以便获取它所需对象的类型。

    抽象工厂模式的 UML 图

    步骤 1

    为形状创建一个接口。

    Shape.java

    public  interface  Shape  {  void  draw(); }
    

    步骤 2

    创建实现接口的实体类。

    Rectangle.java
    public class Rectangle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
    Square.java
    public class Square implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Square::draw() method.");
       }
    }
    Circle.java
    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    

    步骤 3

    为颜色创建一个接口。

    Color.java

    public  interface  Color  {  void  fill(); }
    

    步骤4

    创建实现接口的实体类。

    ## Red.java
    
    public  class  Red  implements  Color  { @Override  public  void  fill()  {  System.out.println("Inside Red::fill() method."); }  }
    
    ## Green.java
    
    public  class  Green  implements  Color  { @Override  public  void  fill()  {  System.out.println("Inside Green::fill() method."); }  }
    
    ## Blue.java
    
    public class Blue implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Blue::fill() method.");
       }
    }
    

    步骤 5

    为 Color 和 Shape 对象创建抽象类来获取工厂。

    ## AbstractFactory.java
    
    public abstract class AbstractFactory {
       public abstract Color getColor(String color);
       public abstract Shape getShape(String shape) ;
    }
    

    步骤 6

    创建扩展了 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;
       }
    }
    
    public class ColorFactory extends AbstractFactory {
        
       @Override
       public Shape getShape(String shapeType){
          return null;
       }
       
       @Override
       public Color getColor(String color) {
          if(color == null){
             return null;
          }        
          if(color.equalsIgnoreCase("RED")){
             return new Red();
          } else if(color.equalsIgnoreCase("GREEN")){
             return new Green();
          } else if(color.equalsIgnoreCase("BLUE")){
             return new Blue();
          }
          return null;
       }
    }
    

    步骤 7

    创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

    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;
       }
    }
    

    步骤 8

    使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。

    ## AbstractFactoryPatternDemo.java
    
    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();
       }
    }
    

    一开始看抽象工厂方法的时候可能会觉得很懵,因为它确实太绕了,即使是范例中这么简单的代码,也需要一些时间去理解,更不要说框架里,库里那代码量了。
    但是其实如果细细推敲,我们会发现理解了工厂模式后,其实抽象工厂模式,无非就是在普通的工厂模式里再加了一个工厂,这个超级工厂里存放着多个工厂,而多个工厂实际上分别就是工厂模式了。而这合在一起就是抽象工厂模式。
    如果我们需要用交通工具代步,可以用轿车,自行车,电动车,飞机,船,多种选择,而交通工具只是一个大类,我们需要选择交通工具的一种型号。因此我们首先要选择一个交通工具,而这个交通工具就是一个工厂方法,那之所用选择抽象工厂方法也就明了了。同样也是简化我们对象的声明,我们可以直接通过声明一个工厂,然后用工厂的方法来声明我们需要的对象,表面上看确实比要直接声明一个对象来的复杂,因为我们还需要一个中间桥梁,但其实是省略了很多对象声明的细节。
    从某种程度上来说,当一个抽象工厂模式,只有一个工厂的时候,那其实就退化成了工厂模式。

    3、单例模式

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    注意:

    • 1、单例类只能有一个实例。
    • 2、单例类必须自己创建自己的唯一实例。
    • 3、单例类必须给所有其他对象提供这一实例。

    介绍

    意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    主要解决:一个全局使用的类频繁地创建与销毁。

    何时使用:当您想控制实例数目,节省系统资源的时候。

    如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

    关键代码:构造函数是私有的。

    应用实例:

    • 1、一个班级只有一个班主任。
    • 2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
    • 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

    优点:

    • 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
    • 2、避免对资源的多重占用(比如写文件操作)。

    缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

    使用场景:

    • 1、要求生产唯一序列号。
    • 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
    • 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

    注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

    实现

    我们将创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。

    SingleObject 类提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo,我们的演示类使用 SingleObject 类来获取 SingleObject 对象。


    步骤 1
    创建一个 Singleton 类。

    SingleObject.java
    public class SingleObject {
     
       //创建 SingleObject 的一个对象
       private static SingleObject instance = new SingleObject();
     
       //让构造函数为 private,这样该类就不会被实例化
       private SingleObject(){}
     
       //获取唯一可用的对象
       public static SingleObject getInstance(){
          return instance;
       }
     
       public void showMessage(){
          System.out.println("Hello World!");
       }
    }
    

    步骤 2
    从 singleton 类获取唯一的对象。

    SingletonPatternDemo.java
    public class SingletonPatternDemo {
       public static void main(String[] args) {
     
          //不合法的构造函数
          //编译时错误:构造函数 SingleObject() 是不可见的
          //SingleObject object = new SingleObject();
     
          //获取唯一可用的对象
          SingleObject object = SingleObject.getInstance();
     
          //显示消息
          object.showMessage();
       }
    }
    

    这个单例模式就很简单了,就是我们通过一个类去得到一个对象,这个过程不用我们new了,类会提供静态方法返回这个对象。这也其实就是创建型模式的目的所在。

    4、建造者模式

    模式的定义与特点

    建造者(Builder)模式的定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

    该模式的主要优点如下:

    1. 各个具体的建造者相互独立,有利于系统的扩展。
    2. 客户端不必知道产品内部组成的细节,便于控制细节风险。

    其缺点如下:

    1. 产品的组成部分必须相同,这限制了其使用范围。
    2. 如果产品的内部变化复杂,该模式会增加很多的建造者类。

    建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

    模式的结构与实现

    建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成,现在我们来分析其基本结构和实现方法。

    1. 模式的结构

    建造者(Builder)模式的主要角色如下。

    1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个滅部件。
    2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
    3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
    4. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

    其结构图如图 1 所示。

    建造者模式的结构图

    图1 建造者模式的结构图

    2. 模式的实现

    图 1 给出了建造者(Builder)模式的主要结构,其相关类的代码如下。

    (1) 产品角色:包含多个组成部件的复杂对象。

    class Product
    {
        private String partA;
        private String partB;
        private String partC;
        public void setPartA(String partA)
        {
            this.partA=partA;
        }
        public void setPartB(String partB)
        {
            this.partB=partB;
        }
        public void setPartC(String partC)
        {
            this.partC=partC;
        }
        public void show()
        {
            //显示产品的特性
        }
    }
    

    (2) 抽象建造者:包含创建产品各个子部件的抽象方法。

    abstract class Builder
    {
        //创建产品对象
        protected Product product=new Product();
        public abstract void buildPartA();
        public abstract void buildPartB();
        public abstract void buildPartC();
        //返回产品对象
        public Product getResult()
        {
            return product;
        }
    }
    

    (3) 具体建造者:实现了抽象建造者接口。

    public class ConcreteBuilder extends Builder
    {
        public void buildPartA()
        {
            product.setPartA("建造 PartA");
        }
        public void buildPartB()
        {
            product.setPartA("建造 PartB");
        }
        public void buildPartC()
        {
            product.setPartA("建造 PartC");
        }
    }
    

    (4) 指挥者:调用建造者中的方法完成复杂对象的创建。

    class Director
    {
        private Builder builder;
        public Director(Builder builder)
        {
            this.builder=builder;
        }
        //产品构建与组装方法
        public Product construct()
        {
            builder.buildPartA();
            builder.buildPartB();
            builder.buildPartC();
            return builder.getResult();
        }
    }
    

    (5) 客户类。

    public class Client
    {
        public static void main(String[] args)
        {
            Builder builder=new ConcreteBuilder();
            Director director=new Director(builder);
            Product product=director.construct();
            product.show();
        }
    }
    

    建造者模式从UML图都可以看得出事非常复杂的,但是这个复杂是相较于其的实现,我们用起来可以说是相当简单了,它将对象的内部复杂实现都给封装了起来,我们根本不需要知道它的实现有多么复杂,我们只需要拿出来用就可以了,这就是建造者模式的优点。
    它就是为了解决一个复杂对象的创建而有的一个模式。通常一个抽象的builder类,可以有多个builder实现类,当我们调用不同的builder类就可以创建出不同的对象,是非常方便的。而我们最终要使用最终的产品,我们只需要交给director类就可以帮我们自行创建了,我们就可以拿来直接用了。大大减少了我们的代码量。这里的director类就是这个模式的重点,他可以帮助我们构建我们需要的对象,并且帮我们把对象的信息全部部署完毕了。看起来其实挺像模板的,但其实并不是。
    它与工厂模式最大的区别就在于,工厂模式更加注重的是对象的创建过程,而这个重点是director类里的组装过程。

    5、原型模式

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

    介绍

    意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    主要解决:在运行期建立和删除原型。

    何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

    如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

    关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

    应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

    优点: 1、性能提高。 2、逃避构造函数的约束。

    缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

    使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

    注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

    实现

    我们将创建一个抽象类 Shape 和扩展了 Shape 类的实体类。下一步是定义类 ShapeCache,该类把 shape 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆。

    PrototypePatternDemo,我们的演示类使用 ShapeCache 类来获取 Shape 对象。

    原型模式的 UML 图

    原型模式看起来比较简单,但是其实他是非常重要的,它已经不再是仅仅的一个设计模式了,相信只要熟悉java基础的,都知道clone()方法,而为什么要有clone()方法呢?如果我们需要一个包含对象引用的变量的副本,我们仅仅的用一个新的变量=这个变量的话,那变量其实是仍然同一个。如果我们在新的变量上进行修改的话,那原变量也会被修改。

    因此我们非常需要一个能够返回新的副本的方法,这就是clone方法,而这个方法就是实现了返回一个副本,这个是一个真正的副本,为什么我们操作int x=0,int a=x,a=2; x没有变化呢,原因那就是基础类型都实现了clone方法。

    相关文章

      网友评论

          本文标题:设计模式概要(一)

          本文链接:https://www.haomeiwen.com/subject/mpkoohtx.html