精华内容
下载资源
问答
  • 创建型设计模式的应用
    千次阅读
    2021-10-16 12:19:00

    创建型设计模式:

    抽象工厂(Abstract Factory):

    1. 用途:提供一个接口以创建一系列相关或相互依赖的对象,而无需指定具体的类。

    2. 场景:

      1. 一个系统要独立于它的产品的创建。
      2. 一个系统要由多个产品系列中的一个来配置。
      3. 强调一系列相关的产品对象的设计以便进行联合使用。
      4. 提供一个产品类库,但只对外提供它们的接口而不是实现
    3. 结构图: 创建一系列相关的对象

      image-20210530093622283

    4. 已知应用:JDK中的Collection,Map

    5. 工厂方法(Factory Method):

      1. 用途:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

      2. 场景:

        1. 一个类不知道它所创建的对象的类。
        2. 一个类希望由它的子类来指定它所创建的对象。
        3. 多用于框架代码中,面向接口编程。
      3. 结构图:创建一个对象

        image-20210530093747954

      4. 已知应用:

        1. JDK中的ThreadPoolExecutor的阻塞队列
        2. AbstractExecutorService.submit方法,在ScheduledThreadPoolExecutor中返回不同的Future

    建造者(Builder):

    1. 用途:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    2. 场景:

      1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
      2. 当构造过程必须允许被构造的对象有不同的表示时。
    3. 结构图: 定义一系列的步骤去创建一类产品

      image-20210530100747814

    4. 已知应用

      1. JDK中的StringBuilder
      2. Spring中的BeanDefinitionBuilder

    单例模式

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

    2. 场景:

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

      单例模式的 UML 图

    原型模式

    1. 用途:实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式

    2. 场景:

      1. 资源优化场景。
      2. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
      3. 性能和安全要求的场景。
      4. 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
      5. 一个对象多个修改者的场景。
    3. 注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

    4. 结构图:clone()方法

      原型模式的 UML 图

    更多相关内容
  • 创建模式 单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式

      本系列文章共分为六篇:
        设计模式(一)设计模式的分类与区别
        设计模式(二)创建型模式介绍及实例
        设计模式(三)结构型模式介绍及实例
        设计模式(四)行为型模式介绍及实例(上)
        设计模式(五)行为型模式介绍及实例(下)
        设计模式(六)设计模式的常见应用

      本篇将介绍创建者模式,创建型模式的主要关注点是“怎样创建对象,使对象的创建与使用分离开来”。

    一、单例模式

    一句话总结:某个类能自行生成全局唯一实例。

    1.1 单例模式定义

      指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

    1.2 单例模式特点

    1. 单例类只有一个实例对象
    2. 该单例对象必须由单例类自行创建
    3. 单例类对外提供一个访问该单例的全局访问点

    1.3 单例模式主要角色

    1. 单例类:包含一个实例且能自行创建这个实例的类。
    2. 访问类:使用单例的类。

      单例模式的UML图,示例如下:

    1.4 单例模式实现方式

      单例模式的实现方式较多,主要方式如下:

    1.4.1懒汉式单例

      该模式的特点是类加载时没有生成单例,只有当第一次调用getlnstance方法时才去创建这个单例。代码示例如下:

    public class Singleton{
        private static Singleton instance=null; 
        //private避免类在外部被实例化   
        private Singleton(){}                               
        public static synchronized Singleton getInstance(){
            //getInstance方法前加同步
            if(instance==null){
                instance=new Singleton();
            }
            return instance;
        }
    }
    

      如果编写的是多线程程序,则不能删除上例代码中的关键字synchronized,否则将存在线程非安全的问题。使用synchronized关键字就可以保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。

    1.4.2 饿汉式单例

      饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。代码示例如下:

    public class Singleton {  
        //在调用getInstance之前就创建一个static对象
        private static final Singleton instance = new Singleton();  
        private Singleton (){}  
        public static Singleton getInstance() {  
            return instance;  
        }  
    }
    
    1.4.3 双重校验锁单例

      该方式既不会在类加载时就初始化单例对象,又合理缩小了synchronized锁的影响范围,安全且在多线程情况下能保持高性能。代码示例如下:

    public class Singleton {  
        private volatile static Singleton singleton;  
        private Singleton (){}  
        public static Singleton getSingleton() {  
            if (singleton == null) {  
                synchronized (Singleton.class) {  
                    if (singleton == null) {  
                        singleton = new Singleton();  
                    }  
                }  
            }  
            return singleton;  
        }  
    }
    

      由于volatile关键字可能会屏蔽掉虚拟机中的一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用 ”双重检查加锁 “ 机制来实现线程安全的单例 , 但并不建议大量采用 , 可以根据情况来选用 。

    1.4.4 静态内部类单例

      该方式通过创建一个静态内部类,在静态内部类中实例化单例,进而达到了延迟实例化的目的。因为外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化单例,故而不占内存。同时,静态内部类中final修饰单例,也达到了安全的目的。代码示例:

    public class Singleton {  
        private static class SingletonHolder {  
             private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
             return SingletonHolder.INSTANCE;  
        }  
    }
    
    1.4.5 枚举式单例

      除了以上四种方式的单例模式,还有用枚举实现的单例模式。上面的双重校验锁单例和静态内部类单例,在不考虑反射场景下,是没有问题的,但是利用反射可以调用private构造方法,所以此时可以使用一种更安全的单例模式:枚举式单例。这种方式可以反序列化
      之所以可以使用枚举来实现单例,是因为:枚举中的构造方法默认为private,其被设计成是单例模式,JVM为了保证每一个枚举类元素的唯一实例,不允许外部通过new来创建的,所以会把构造函数设计成private,防止用户生成实例。示例代码如下:

    public class Singleton {
    }
    
    public enum  SingletonEnum {
    	SINGLETON;
    	private Singleton instance;
    	private SingletonEnum(){
    		instance = new Singleton();
    	}
    
    	public Singleton getInstance(){
    		return instance;
    	}
    }
    

      生成单例的方式示例:

    	Singleton singleton1 = SingletonEnum.SINGLETON.getInstance();
    
    1.4.6 几种单例创建方式的比较
    类别特点
    饿汉式类初始化时创建单例例,线程安全,适用于单例例占内存小的场景,否则推荐使用懒汉式延迟加载
    懒汉式需要创建单例例实例例的时候再创建,需要考虑线程安全(性能不不太好)
    双重检验锁效率高,线程安全
    静态内部类方式可以同时保证延迟加载和线程安全
    枚举方式使用枚举除了了线程安全和防止反射调用构造器器之外,还提供了自动序列列化机制,防止反序列列化的时候创建新的对象

    1.5 单例模式应用场景

    1. 某类只要求生成一个对象(比如唯一序列号)的时候。
    2. 当对象需要被共享(比如例如一个Web页面上的计数器)的场合,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。
    3. 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
    4. 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。

    二、工厂方法模式

      被创建的对象称为产品,把创建产品的对象称为工厂。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式"。本节介绍的“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品。

    一句话总结:由实现工厂接口的具体子类工厂决定生成什么产品,产品是一类的。

    2.1 工厂方法模式定义

      定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子类工厂当中

    2.2 工厂方法模式主要角色

      工厂方法模式UML类图如下:

      工厂方法模式实现时,客户端需要决定实例化哪一个具体的类时,选择判断的问题还是存在的。也就是说工厂方法把简单工厂的内部逻辑判断转移到了客户端进行。

    2.3 工厂方法模式特点

    优点

    1. 只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
    2. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。

    缺点

    1. 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

    工厂方法的缺点可以通过和反射结合来改进

    2.4 工厂方法模式实现方式

      工厂方法模式的实现,以播放不同公司的不同类型电影为例。产品有两种:动作电影和喜剧电影,工厂也有两种:Fox公司和WBP公司,从不同的工厂里可以生成不同类型的电影,从而达到多样产品类型的目的。代码示例如下:

    //抽象产品:电影
    public interface  Movie {
    	void play();
    }
    
    //具体产品1:动作电影
    public class ActionMovie implements Movie {
    	private String factory;
    	public ActionMovie(String factory){
          this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ActionMovie is playing");	
    	}
    }
    
    //具体产品2:喜剧电影
    public class ComedyMovie implements Movie {
    	private String factory;
    	public ComedyMovie(String factory){
    		this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ComedyMovie is playing");
    	}
    }
    
    //抽象工厂
    public interface Factory {
        Movie getActionMovie();
        Movie getComedyMovie();
    }
    
    //具体工厂1:Fox公司
    public class FoxFactory implements Factory{
        public Movie getActionMovie(){  return new ActionMovie("Fox");  }
        public Movie getComedyMovie(){	return new ComedyMovie("Fox");  }
    }
    
    //具体工厂2:WBP公司
    public class WBPFactory implements Factory{
        public Movie getActionMovie(){	return new ActionMovie("WBP");  }
        public Movie getComedyMovie(){	return new ComedyMovie("WBP");  }
    }
    
    //测试类
    public class FactoryTest {
        public static void main(String[] args) {  
        	Factory foxFactory = new FoxFactory();  
            Movie actionMovie = foxFactory.getActionMovie();  
            actionMovie.play();  
            Movie comedyMovie = foxFactory.getComedyMovie();  
            comedyMovie.play(); 
        	Factory WBPFactory = new WBPFactory();  
            actionMovie = WBPFactory.getActionMovie();  
            actionMovie.play();  
            comedyMovie = WBPFactory.getComedyMovie();  
            comedyMovie.play(); 
        }  
    }
    

      结果示例:

    Fox ActionMovie is playing
    Fox ComedyMovie is playing
    WBP ActionMovie is playing
    WBP ComedyMovie is playing
    

    2.5 工厂方法模式应用场景

    1. 客户只知道创建产品的工厂名,而不知道具体的产品名
    2. 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口
    3. 客户不关心创建产品的细节,只关心产品的品牌
    4. jdbc 连接数据库,降低对象的产生和销毁。

    三、抽象工厂模式

      上一节的工厂方法模式只能产生一类产品(一种顶级抽象接口),如果需要产生多类产品/产品族(将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族),就要使用抽象工厂模式。也就是说,抽象工厂相对于工厂模式,差异之处在于能生产多等级产品。
      要达到生产一个产品族的目的话,其实也能想到:在一个抽象工厂的层级上再抽象出一层定义生产一个产品组的顶级抽象工厂。可以参考这张表来理解:
    在这里插入图片描述

    一句话总结:由实现工厂接口的具体子类工厂决定生成什么产品,产品是多类的。

    3.1 抽象工厂模式定义

      一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

    3.2 抽象工厂模式主要角色

      抽象工厂模式UML图示如下:

      AbstractProductA和AbstractProductB是两个抽象产品,ProductA1、ProductA2、ProductB1、ProductB2是对两个抽象产品的具体实现;IFactory是一个抽象工厂接口,它里面包含所有产品创建的抽象方法。

    3.3 抽象工厂模式特点

    优点

    1. 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
    2. 当增加一个新的产品族时不需要修改原代码,满足开闭原则。

    缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

    3.4 抽象工厂模式实现方式

      本章节的例子不是很好,例子可以参考这篇文章:抽象工厂模式和工厂方法模式区别
      抽象工厂模式的实现,此处依然以影视作品为例,不同的产品为:电视剧和电影,工厂为不同的公司福克斯公司和华纳兄弟公司。和上个章节的功能相比,多了生成“电视剧”产品的功能。代码示例如下:

    //抽象产品1:电影
    public interface  Movie {
    	void play();
    }
    
    //具体产品1:动作电影
    public class ActionMovie implements Movie {
    	private String factory;
    	public ActionMovie(String factory){
          this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ActionMovie is playing");	
    	}
    }
    
    //具体产品2:喜剧电影
    public class ComedyMovie implements Movie {
    	private String factory;
    	public ComedyMovie(String factory){
    		this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ComedyMovie is playing");
    	}
    }
    
    //抽象产品2:电视剧
    public interface TVSeries {
    	void play();
    }
    
    //具体产品2:动作电视剧
    public class ActionTVSeries  implements TVSeries{
    	private String factory;
    	public ActionTVSeries(String factory){
          this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ActionTVSeries is playing");	
    	}
    }
    
    //具体产品2:喜剧电视剧
    public class ComedyTVSeries implements TVSeries{
    	private String factory;
    	public ComedyTVSeries(String factory){
          this.factory = factory;
    	}
    	public void play() {
    		System.out.println(factory+" ComedyTVSeries is playing");	
    	}
    }
    
    //抽象工厂
    public interface Factory {
        Movie getActionMovie();
        Movie getComedyMovie();
        TVSeries getActionTVSeries();
        TVSeries getComedyTVSeries();
    }
    
    //具体工厂1:20世纪 福克斯公司
    public class FoxFactory implements Factory{
        public Movie getActionMovie(){   return new ActionMovie("Fox");  }
        public Movie getComedyMovie(){   return new ComedyMovie("Fox");  }
    	public TVSeries getActionTVSeries() {	return new ActionTVSeries("Fox");  }
    	public TVSeries getComedyTVSeries() {	return new ComedyTVSeries("Fox");  }
    }
    
    //具体工厂2:华纳兄弟公司
    public class WBPFactory implements Factory{
        public Movie getActionMovie(){	return new ActionMovie("WBP");   }
        public Movie getComedyMovie(){	return new ComedyMovie("WBP");   }
    	public TVSeries getActionTVSeries() {	return new ComedyTVSeries("WBP");  }
    	public TVSeries getComedyTVSeries() {	return new ComedyTVSeries("WBP");  }
    }
    
    //测试类
    public class FactoryTest {
        public static void main(String[] args) {  
        	Factory foxFactory = new FoxFactory();  
            Movie actionMovie = foxFactory.getActionMovie();  
            actionMovie.play();  
            Movie comedyMovie = foxFactory.getComedyMovie();  
            comedyMovie.play(); 
            TVSeries actionTVSeries = foxFactory.getActionTVSeries();
            actionTVSeries.play();
            TVSeries comedyTVSeries = foxFactory.getComedyTVSeries();
            comedyTVSeries.play();
        	Factory WBPFactory = new WBPFactory();  
            actionMovie = WBPFactory.getActionMovie();  
            actionMovie.play();  
            comedyMovie = WBPFactory.getComedyMovie();  
            comedyMovie.play(); 
            actionTVSeries = WBPFactory.getActionTVSeries();
            actionTVSeries.play();
            comedyTVSeries = WBPFactory.getComedyTVSeries();
            comedyTVSeries.play();
        }  
    }
    

      结果示例:

    Fox ActionMovie is playing
    Fox ComedyMovie is playing
    Fox ActionTVSeries is playing
    Fox ComedyTVSeries is playing
    WBP ActionMovie is playing
    WBP ComedyMovie is playing
    WBP ComedyTVSeries is playing
    WBP ComedyTVSeries is playing
    

    3.5 抽象工厂模式应用场景

    1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时。
    2. 系统中有多个产品族,但每次只使用其中的某一族产品。
    3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

    四、建造者模式

      建造者模式常常用来创建复杂的产品,此模式中,会有一个专业的建造者(Build)类负责复杂产品(可以进行分部构建)的具体创建过程,从而达到对象创建和使用分离的目的。

    一句话总结:将复杂的对象分解为多个简单的对象,然后分步骤构建。

    4.1 建造者模式定义

      指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示

    4.2 建造者模式特点

    优点

    1. 各个具体的建造者相互独立,有利于系统的扩展。
    2. 客户端不必知道产品内部组成的细节,便于控制细节风险。
    3. 可以对构造过程进行更精细化的控制。

    缺点

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

    4.3 建造者模式主要角色

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

      建造者模式结构图如下:

    4.4 建造者模式实现方式

      此处以一个较复杂的产品创建过程为例,该产品包括partA、partB、partC三个模块,这三个模块需要分开创建,代码示例如下:

    //包含复杂组件的产品类
    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(){
        	System.out.println("partA:"+partA+"\npartB:"+partB+"\npartC:"+partC);	
        }
    }
    
    //抽象建造者,一般定义各个组件的建造过程和返回对象接口
    public 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;
        }
    }
    
    //具体建造者
    public class ConcreteBuilder extends Builder{
        public void buildPartA(){
            product.setPartA("AAA");
        }
        public void buildPartB(){
            product.setPartB("BBB");
        }
        public void buildPartC(){
            product.setPartC("CCC");
        }
    }
    
    //指挥者
    public class Director{
        private Builder builder;
        public Director(Builder builder){
            this.builder=builder;
        }
        //产品构建与组装方法
        public Product construct(){
            builder.buildPartA();
            builder.buildPartB();
            builder.buildPartC();
            return builder.getResult();
        }
    }
    
    //测试类
    public class BuildTest{
        public static void main(String[] args){
            Builder builder=new ConcreteBuilder();
            Director director=new Director(builder);
            //此处的例子还有更常见的写法,如:
            //builder.buildPartA().buildPartB().buildPartC();
            Product product=director.construct();
            product.show();
        }
    }
    

      结果示例:

    partA:AAA
    partB:BBB
    partC:CCC
    

    4.5 建造者模式应用场景

    1. 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
    2. 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
    3. 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
    4. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。

    五、原型模式

      在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,此时就需要用原型模式来创建对象。
      Java是自带原型模式的。要实现原型模式需要实现Cloneable接口,重写clone接口。

    一句话总结:利用现有对象创建相同或相似对象。

    5.1 原型模式定义

      用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

    5.2 原型模式主要角色

      原型模式UML图示如下:

    1. 抽象原型类(Cloneable)
       规定了具体原型对象必须实现的clone接口。
    2. 具体原型类(ConcretePrototype)
       实现抽象原型类的clone方法,它是可被复制的对象。
    3. 访问类
       使用具体原型类中的clone方法来复制新的对象。

    5.3 原型模式特点

    优点

    1. 性能提高。原型模式是在内存二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
    2. 逃避构造函数的约束。这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要在实际应用时考虑。

    缺点

    1. 对于现有类,进行克隆可能实现起来较为复杂。

    5.4 原型模式实现方式

      原型模式的实现,有两种方式:深克隆与浅克隆。浅克隆是创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址;深克隆是创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
      注意: 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一 是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是 一个原始类型或不可变对象。
      代码示例:

    5.4.1 浅克隆实现
    //抽象原型,原生的Cloneable接口
    public interface Cloneable {
    }
    //具体原型
    public class ConcretePrototype implements Cloneable {
        private String name;
        private int id;
        public Object clone(){
            ConcretePrototype prototype = null;
    		try {
    			prototype = (ConcretePrototype)super.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
            return prototype;
        }
        public String getName() {    return name;    }
        public void setName(String name) {   
            this.name = name;    
        }
    	public int getId() {	return id;   }
    	public void setId(int id) {
    		this.id = id;
    	}
    }
    
    //访问类&测试类
    public class PrototypeTest {
        public static void main(String[] args) {  
        	ConcretePrototype prototype = new ConcretePrototype();
            prototype.setName("exp");
            ConcretePrototype prototype2 = (ConcretePrototype) prototype.clone();
        	System.out.println("prototype is equals prototype2?"+prototype.equals(prototype2));
        }
    }
    

      结果示例:

    prototype is equals prototype2?false
    
    5.4.2 深克隆实现

      深克隆可以用序列化的方式来实现(深克隆还可以通过在clone方法里再clone一遍引用对象实现,当然,此时所引用的对象也要实现Cloneable接口),即实现Serializable接口。示例代码如下:

    /*具体原型*/
    public class ConcretePrototype implements Serializable {
        private String name;
        private int id;
        public ConcretePrototype clone(){
        	//将对象写入流中
        	ByteArrayOutputStream bao = new ByteArrayOutputStream();
        	ObjectOutputStream oos;
        	ObjectInputStream ois;
    		try {
    			oos = new ObjectOutputStream(bao);
    			oos.writeObject(this);
    	    	//将对象取出来
    	    	ByteArrayInputStream bi = new ByteArrayInputStream(bao.toByteArray());
    	    	ois = new ObjectInputStream(bi);
    	    	try {
    				return (ConcretePrototype)ois.readObject();
    			} catch (ClassNotFoundException e) {
    				e.printStackTrace();
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		return null;
        }
        public String getName() {    return name;   }
        public void setName(String name) {
            this.name = name;
        }
    	public int getId() {	return id;    }
    	public void setId(int id) {
    		this.id = id;
    	}
    }
    /*测试类*/
    public class PrototypeTest {
        public static void main(String[] args) {  
        	ConcretePrototype prototype = new ConcretePrototype();
            prototype.setName("exp");
            prototype.setId(1);
            ConcretePrototype prototype2 = (ConcretePrototype) prototype.clone();
        	System.out.println("prototype is equals prototype2?"+prototype.equals(prototype2));
        	System.out.println("prototype2.getName():"+prototype2.getName()+",prototype2.getId():"+prototype2.getId());
        }
    }
    

      结果示例:

    prototype is equals prototype2?false
    prototype2.getName():exp,prototype2.getId():1
    

      同时,当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆。

    5.5 原型模式应用场景

    1. 对象之间相同或相似,常见的情况是:只有几个属性不同。
    2. 对象的创建过程比较麻烦,但复制比较简单的时候。
    3. 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
    4. 资源优化场景
        类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
    5. 性能和安全要求的场景
        通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
    6. 一个对象多个修改者的场景
        一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
    展开全文
  • ③通过编程实践,理解每一种创建型设计模式的概念和内涵、结构、优缺点以及应用场景。 (2)实验内容与步骤 ①使用简单工厂模式设计一个可以创建不同几何形状( Shape)(例如圆形( Circle).、矩形 Rectangle)和三角形...

    实验项目二: 创建型设计模式实验

    (1)实验目的与原理
    ①结合实例,熟练绘制创建型设计模式结构图。
    ②结合实例,熟练使用Java面向对象编程语言实现创建型设计模式。
    ③通过编程实践,理解每一种创建型设计模式的概念和内涵、结构、优缺点以及应用场景。
    (2)实验内容与步骤
    ①使用简单工厂模式设计一个可以创建不同几何形状( Shape)(例如圆形( Circle).、矩形 Rectangle)和三角形( ( Triangle)等的绘图工具类,每个几何图形均具有绘制方法daw()和擦除方法 erase(),要求在绘制不支持的几何图形时,抛出一个 UnsupportedShapeException异常。绘制类图并编程模拟实现。

    ②在某网络管理软件中,需要为不同的网络协议提供不同的连接类,例如针对POP3协议的连接类POP3Connection、针对IMAP协议的连接类 IMAPConnection、针对HTTP协议的连接类 HTTPConnection等。由于网络连接对象的创建过程较为复杂,需要将其创建过程封装到专门的类中,该软件还将支持更多类型的网络协议。现采用工厂方法模式进行设计,绘制类图并编程模拟实现。

    ③某系统为了改进数据库操作的性能,用户可以自定义数据库连接对象 Connection和语句对象 Statement,针对不同类型的数据库提供不同的连接对象和语句对象,例如提供 Oracle或 MySQL专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。使用抽象工厂模式设计该系统,绘制对应的类图并编程模拟实现。

    ④在某赛车游戏中,赛车包括方程式赛车、场地野赛车、运动汽车、卡车等类型,不同类型的赛车的车身、发动机、轮胎、变速箱等部件有所区别。玩家可以自行选择赛车类型,系统将根据玩家的选择创建出一辆完整的赛车。现采用建造者模式实现赛车的构建,绘制对应的类图并编程模拟实现

    ⑤某在线招聘网站中,用户可以创建一个简历模板。针对不同的工作岗位,可以复制该简历模板并进行适当修改后,生成一份新的简历。在复制简历时,用户可以选择是否复制简历中的照片:如果选择“是”,则照片将一同被复制,用户对新简历中的照片进行修改不会影响到简历模板中的照片,对模板进行修改也不会影响到新简历;如果选择“否”,则直接引用简历模板中的照片,修改简历模板中的照片将导致新简历中的照片一同修改,反之亦然。现采用原型模式设计该简历复制功能并提供浅克隆和深克隆两套实现方案,绘制对应的类图并编程模拟实现。

    ⑥某Web性能测试软件中包含一个虚拟用户生成器( Virtual User Generator)。为了避免生成的虚拟用户数量不一致,该测试软件在工作时只允许启动唯一一个虚拟用户生成器。采用单例模式设计该虚拟用户生成器,绘制类图并分别使用饿汉式单例、双重检测锁等二种方式编程模拟实现。

    (3)实验过程
    第一题:简单工厂模式实现创建不同几何图形
    结构类图
    在这里插入图片描述
    实现代码:

    模拟测试截图
    在这里插入图片描述
    第二题:工厂方法模式实现不同网络协议的连接
    结构类图
    在这里插入图片描述

    实现代码:

    模拟测试截图
    在这里插入图片描述

    第三题:抽象工厂模式实现数据库的连接
    结构类图
    在这里插入图片描述

    实现代码:

    模拟测试截图
    在这里插入图片描述

    第四题:建造者模式实现赛车的构建
    结构类图
    在这里插入图片描述

    实现代码:

    模拟测试截图
    在这里插入图片描述

    第五题:原型模式通过浅克隆和深克隆方法实现该简历复制功能
    结构类图
    在这里插入图片描述

    实现代码:

    模拟测试截图
    在这里插入图片描述

    第六题:单例模式设计虚拟用户生成器,使用饿汉式和双重检测
    结构类图
    在这里插入图片描述

    实现代码:

    模拟测试截图
    在这里插入图片描述
    详细的代码及操作

    展开全文
  • 设计模式 ① — 创建型模式

    千次阅读 2018-06-07 11:24:26
    创建型模式: 负责对象的创建。工厂方法模式(Factory Method);解决某个对象的创建工作。抽象工厂模式(Abstract Factory): 解决一系列相互依赖对象的创建工作。创建者模式(Builder):解决“一些复杂对象”的...

    创建型模式: 负责对象的创建。

    工厂方法模式(Factory Method);解决某个对象的创建工作。

    抽象工厂模式(Abstract Factory): 解决一系列相互依赖对象的创建工作。

    创建者模式(Builder):解决“一些复杂对象”的创建工作。

    原型模式(Prototype):解决某些结构复杂的对象的创建工作。

    单例模式(Singleton):解决了实体对象的个数问题。

          单例模式(SINGLETON

    基础概念:

    介绍:

    单例对象的类保证只有一个实例存在。

    定义:

    确保某个类只有一个实例,向整个系统提供这个实例。

    使用场景:

    确保某个类只有一个对象场景,避免产生多个对象消耗过多的资源,或者某种类型的对象因该有且只有一个。

    UML图:

     

     

    Client : 高层客户端。

    Singleton : 单例类。

     

    Android源码里的实现:

    常见的写法(线程不安全):

    推荐的写法(线程安全;延迟加载;效率较高)

     

    双重检查:

    静态内部类

    枚举的写法:

    Android不推荐枚举,耗费资源:

    https://www.youtube.com/watch?t=32&v=Hzs6OBcvNQE

    在Android项目里常用于生成View的LayoutInflater,就是单例的一种实现。

         工厂方法模式(FACTORY

    介绍:

    工厂方法模式是创建型设计模式之一 。

    定义:

    工厂方法模式定义一个创建对象的接口,让子类决定实例化哪个类 。

     

    使用场景:

    需要生成复杂对象的地方适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式。 

     

    UML图:

    Android源码里的实现:

    ActivityonCreate就可以看作是一个工厂方法 。 

    优点:

    减少内存开销,提高性能。

    缺点:

    每次添加新的产品就要编写一个新的产品类,导致类结构的复杂化。

      抽象工厂方法(ABSTRACT FACTORY

    介绍:

    抽象工厂模式起源于以前对不同操作系统的图形化解决方案,不同操作系统中的按钮和文本控件实现不同,展示效果也不一样。 

    定义:

    为创建一组相关或者是相互依赖的对象提供一个接口,而不需要指定它们的具体类。 

    使用场景:

    一个家族有相同的约束时可以使用抽象工厂模式。 

    UML图:

    AbstractFactory : 抽象工厂角色,声明了一组用于创建一个产品的方法,每个方法对应一种产品。

    ConcreteFactory : 具体工厂角色,实现了在抽象工厂中定义的创建产品的方法,生成一组具体产品,产品构成一个产品种类。

    AbstractProduct : 抽象产品角色,为每种产品声明接口,比如图中AbstractProductAB

    ConcreteProduct : 具体产品角色,定义具体工厂生产的具体产品对象,如图中ConcreteProductA1,A2,B1B2

     

    Android源码里的实现:

    Android里对MediaPlayer的创建。

    优点:

    分离接口和实现。

    缺点:

    1. 类文件爆炸性增加

    2. 不容易扩展新的产品类,因为每增加一个产品类就需要修改抽象工厂。

    工厂方法和抽象工厂的区别:


    区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
        工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

          原型模式(PROTOTYPE

    介绍:

    原型二字表明了该模式有一个样板实例,用户从这个样本实例中复制一个内部属性一致的对象,原型模式多用于创建复杂的或构造耗时的实例。 

    定义:

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

    使用场景:

    1.类初始化需要消耗非常多的资源,包括数据,硬件资源等,通过原型拷贝避免消耗。

    2.一个对象需要提供给其他对象访问,各个调用者需要修改其值时,考虑原型模式拷贝或者多个对象供调用者使用,即保护性拷贝。 

     

    UML图:

    Client : 客户端用户。

    Prototype : 抽象类或者接口,声明具备clone能力。

    ConcretePrototype : 具体原型类。

     

    Android源码里的实现:

    Intentclone()方法。

     

    优点:

    原型模式是在内存中二进制流的拷贝,比直接new一个对象性能好很多,当要在一个循环体内产生大量的对象时,原型模式可以更好体现其优点。

    缺点:

    直接在内存中拷贝时,构造器是不会执行的,优点是减少了约束,缺点也是减少了约束。

          建造者模式(BUILD

    介绍:

    Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,更精细的控制对象构造流程。 

    定义:

    将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。 

    使用场景:

    1. 初始化一个对象特别复杂,参数多,很多参数都有默认值时。比如ImageLoader里的ImageLoaderConfig

    2. 类非常复杂,产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常适合。 

     

    UML图:

    Product : 产品的抽象类。

    Builder : 抽象Builder类,规范产品的组建,一般是子类实现具体的组建过程。

    ConcreteBuilder : 具体的Builder类。

    Director : 统一组装过程。

    Android源码里的实现:

    WindowManager

     

    优点: 

    1. 良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节。

    2. 建造者独立,容易扩展。

    缺点: 

    会产生多余的Builder对象和Director对象,消耗内存。

    展开全文
  • Java设计模式创建型模式

    千次阅读 2016-05-12 16:11:07
    单例模式 应用场合: 在一个JVM中,该对象只需有一个实例存在 特点: 对于创建频繁的大型对象可以降低系统开销 减轻GC压力(Garbage collection) 安全(核心交易引擎) 实现方式: 加载类时直接创建类的实例...
  • 设计模式创建型模式

    千次阅读 2019-03-31 12:17:53
    设计模式创建型模式:单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。介绍意图:将一个复杂的构建与其表示相分离,使得同样的构建过程...
  • 创建型模式应用实验
  • 工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂方法模式、抽象工厂模式;简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的...
  • 【面向对象】——设计模式创建型模式

    千次阅读 热门讨论 2014-12-23 14:52:15
    创建型模式创建型模式抽象了实例化的过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。创建型模式都会讲关于该系统使用哪些具体的类的信息封装起来。允许客户用结构和功能差别很大的“产品”对象...
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高...
  • Java常见设计模式总结

    万次阅读 多人点赞 2021-09-18 17:18:54
    设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都...总体来说,设计模式分为三大类:5种创建型模式、7种结构型模式、11种行为型模式
  • 设计模式--创建型模式-单例模式

    万次阅读 2021-02-01 18:10:29
    单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 问题 单例模式同时解决了两个问题, 所以违反了_单一职责原则_: 1. 保证一个类只有一个实例。 2. 为该实例...
  • 来认识认识建造者模式
  • 常用设计模式在实际开发中的应用

    千次阅读 2021-01-21 11:24:04
    设计模式在实际开发中的应用一、设计模式的定义二、设计模式的分类三、面向对象七大原则四、设计模式在实际开发中的应用插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左...
  • 前言第1章Python的创建型设计模式 1.1抽象工厂模式 1.1.1经典的抽象工厂模式 1.1.2Python风格的抽象工厂模式 1.2建造者模式 1.3工厂方法模式 1.4原型模式 1.5单例模式第2章Python的结构型设计模式 2.1适配器...
  • 设计模式 | 适配器模式及典型应用

    万次阅读 多人点赞 2018-09-20 01:37:29
    适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。 根据适配器类与适配者类的关系不同...
  • java设计模式之结构型设计模式

    千次阅读 2021-10-16 12:20:15
    结构型设计模式: 适配器(Adapter): 用途:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。 场景: 你想使用一个已经存在的类,而它的...
  • 论软件设计模式及其应用

    千次阅读 2019-10-20 18:29:11
    摘要:  2018年上半年,我在XX电子责任有限公司,作为气候组组长参与了陕西气象监测业务系统的开发。在之前我们已经开发了甘、宁两省的监测业务系统。陕西在全国也算气象大省,而且独特的地理...我决定使用设计模式进...
  • 23种设计模式应用场景

    千次阅读 2021-01-14 22:00:26
    设计模式六大原则 创建型模式 工厂方法模式-日志工厂 抽象工厂模式-多平台软件设计 单例模式-序列号生成器 建造者模式-万能的乐高 原型模式-广告邮件推送 结构型模式 适配器模式-日志适配器 桥接模式-支付功能的扩展...
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。介绍意图:定义一个创建对象的...
  • Android设计模式应用场景

    千次阅读 2020-10-09 14:47:34
    设计模式一般分为三类:创建型模式、结构型模式、行为型模式 1.1 创建型模式(5种) (口诀:单抽工建原) 用来创建对象的。一共有五种:单例模式、原型模式、建造者模式、工厂方法模式、抽象工厂模式、。 [单例模式] ...
  • 设计模式--六种创建型模式

    千次阅读 热门讨论 2017-04-13 16:58:25
     每几种模式之间都有一定的联系,从中发现它们的相同点和不同点,研究发生改变的节点,这就是本篇博客所要说明的创建型设计模式之间的联系。它们包括:简单工厂模式、单例模式、工厂方法模式、抽象工厂模式、建造者...
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,...
  • TS创建型设计模式之单例模式

    千次阅读 2019-01-15 00:12:47
    定义 Ensure a class has only one instance,and provide a global point ...应用(例子) //懒汉式单例又称惰性单例,前端不考虑,如果是后端可能会考虑高并发的情况下出现多个实例 class LazySingle { private ...
  • 设计模式 | 组合模式及典型应用

    千次阅读 多人点赞 2018-10-05 17:36:55
    本文的主要内容: 介绍组合模式 示例 组合模式总结 源码分析组合模式的典型应用 ...设计模式 | 简单工厂模式及典型应用 设计模式 | 工厂方法模式及典型应用 设计模式 | 抽象工厂模式及典型应用 设计模式 ...
  •  每几种模式之间都有一定的联系,从中发现它们的相同点和不同点,研究发生改变的节点,这就是本篇博客所要说明的创建型设计模式之间的联系。它们包括:简单工厂模式、单例模式、工厂方法模式、抽象工厂模式、建造者...
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。介绍意图:提供一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 296,449
精华内容 118,579
关键字:

创建型设计模式的应用