精华内容
下载资源
问答
  • 2018-06-19 11:41:20
    建造者模式 Builder Pattern 使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
    介绍

    意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
    主要解决:
    更多相关内容
  • Java 创建模式

    千次阅读 2021-10-28 09:59:36
    Java 创建模式 持续更新… 创建模式的主要关注点是‘怎样创建对象?’,它的主要特点是‘将对象的创建和使用分离’。 这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。 创建模式分为: 单例...

    Java 创建型模式

    持续更新…

    创建者模式的主要关注点是‘怎样创建对象?’,它的主要特点是‘将对象的创建和使用分离’。
    这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。
    创建型模式分为:
    • 单例模式
    • 工厂方法模式
    • 抽象工厂模式
    • 原型模式
    • 建造者模式

    单例模式

    单例模式是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种出创建对象的最佳方式。
    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类对象。

    单例模式的结构

    单例模式主要有以下角色:

    • 单例类,只能创建一个实例的类
    • 访问类,使用单例的类

    点击此可以查看更多有关单例模式的细节

    工厂模式

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

    UML类图实例:

    BookStore +sellBook(String type) : NoteBook «abstract» NoteBook #writeContent(String content) : void EnglishBook -String type -String content +getContent() : String +getDescription() : String MathBook -String type -String content +getContent() : String +getDescription() : String

    代码实现如下:

    package com.wu;
    
    public abstract class NoteBook {
        public abstract  void writeContent(String content);
    }	
    
    package com.wu;
    
    public class EnglishBook extends NoteBook{
        private static final String TYPE = "英语本";
        private String content;
    
        public void writeContent(String content){
            this.content = content;
        }
        public String getContent(){
            return "内容为:" + content;
        }
        public String getDescription(){
            return "这是一个英语本";
        }
    }
    
    package com.wu;
    
    public class MathBook extends NoteBook{
        private static final String TYPE = "数学本";
        private String content;
    
        public void writeContent(String content){
            this.content = content;
        }
        public String getContent(){
            return "内容为:" + content;
        }
        public String getDescription(){
            return "这是一个数学本";
        }
    }
    
    package com.wu;
    
    public class BookStore {
        public NoteBook sellBook(String type) throws RuntimeException{
            NoteBook book = null;
            if(type.equals("英语本")){
                book =  new EnglishBook();
            }else if(type.equals("数学本")){
                book = new MathBook();
            }else{
                throw new  RuntimeException();
            }
            return book;
        }
    }
    
    
    package com.wu;
    
    public class Client {
        public static void main(String[] args) {
            // 创建书店对象
            BookStore booKStore = new BookStore();
            // 销售数学本
            NoteBook book = booKStore.sellBook("数学本");
            System.out.println(((MathBook) book).getDescription());
            // 销售英语本
            book = booKStore.sellBook("英语本");
            System.out.println(((MathBook) book).getDescription());
        }
    }
    

    可以分析以上的代码,由于通过BookStore来创建(new)Book对象,所以导致了BookStore对Book对象的耦合,假如我们需要更换对象的时候,就会修改相应的代码,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只需要和工厂来进行信息交换就可以了,就可以彻底和对象解耦,因此,工厂模式的最大优势就是:解耦合

    三种工厂模式

    • 简单工厂模式(不属于经典设计模式)
    • 工厂方法模式
    • 抽象工厂模式

    简单工厂模式

    简单工厂角色

    • 抽象产品:定义了产品规范
    • 具体产品:实现或者继承抽象产品的子类
    • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品

    优缺点

    • 优点:
      封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就可以避免了修改客户代码,如果要实现新的产品就可以直接修改工厂类,而不需要原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
    • 缺点:
      增加新的产品还是需要修改工厂类的代码,违背了“开闭原则”

    UML类图:

    BookStore +sellBook(String type) : NoteBook SimpleBookFactory +createBook(String type) : NoteBook «abstract» NoteBook #writeContent(String content) : void EnglishBook -String type -String content +getContent() : String +getDescription() : String MathBook -String type -String content +getContent() : String +getDescription() : String

    修改的代码:

    package com.wu;
    
    public class SimpleBookFactory {
        public NoteBook createBook(String type){
            NoteBook noteBook = null;
            if(type.equals("英语本")){
                noteBook =  new EnglishNoteBook();
            }else if(type.equals("数学本")){
                noteBook = new MathNoteBook();
            }else{
                throw new  RuntimeException();
            }
            return noteBook;
        }
    }
    
    package com.wu;
    
    public class BookStore {
        public NoteBook sellBook(String type) throws RuntimeException{
            SimpleBookFactory factory = new SimpleBookFactory();
            NoteBook noteBook = factory.createBook(type);
            return noteBook;
        }
    }
    
    

    静态工厂:

    package com.wu;
    
    public class SimpleBookFactory {
        public static NoteBook createBook(String type){
            NoteBook noteBook = null;
            if(type.equals("英语本")){
                noteBook =  new EnglishNoteBook();
            }else if(type.equals("数学本")){
                noteBook = new MathNoteBook();
            }else{
                throw new  RuntimeException();
            }
            return noteBook;
        }
    }
    

    工厂方法模式

    针对上面中的未遵循开闭原则,我们可以通过工厂方法模式来完美地解决。

    概念
    定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法

    工厂方法模式角色

    • 抽象工厂:提供了创建产品的接口,调用者通过它访问具体的工厂的工厂方法来创建产品。
    • 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品:定义了产品规范,描述了产品的主要特性和功能。
    • 具体产品:实现了抽象产品角色所定义的接口,有具体工厂来创建,它同具体工厂之间一一对应。

    优缺点

    • 优点:
      用户只需要知道具体工厂的名称就可以得到所要的产品,无须知道产品的具体创建过程
      在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
    • 缺点:
      每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度

    UML类图:

    BookStore +sellBook() : NoteBook «interface» BookFactory +createBook() : NoteBook «abstract» NoteBook #writeContent(String content) : void EnglishBookFactory +createBook() : NoteBook MathBookFactory +createBook() : NoteBook EnglishBook -String type -String content +getContent() : String +getDescription() : String MathBook -String type -String content +getContent() : String +getDescription() : String

    代码实现:

    package com.wu;
    
    public class BookStore {
        private BookFactory factory;
    
        public void setFactory(BookFactory factory) {
            this.factory = factory;
        }
    
        public NoteBook sellBook() throws RuntimeException{
            NoteBook book = factory.createBook();
            return book;
        }
    }
    
    package com.wu;
    
    public abstract class NoteBook {
        public abstract  void writeContent(String content);
    }
    
    
    package com.wu;
    
    public interface BookFactory {
        public NoteBook createBook();
    }
    
    
    package com.wu;
    
    public class MathBookFactory implements BookFactory{
    
        @Override
        public NoteBook createBook() {
            return new MathNoteBook();
        }
    }
    
    
    package com.wu;
    
    public class EnglishBookFactory implements BookFactory{
    
        @Override
        public NoteBook createBook() {
            return new EnglishNoteBook();
        }
    }
    
    
    package com.wu;
    
    public class MathNoteBook extends NoteBook {
        private static final String TYPE = "数学本";
        private String content;
    
        public void writeContent(String content){
            this.content = content;
        }
        public String getContent(){
            return "内容为:" + content;
        }
        public String getDescription(){
            return "这是一个数学本";
        }
    }
    
    
    package com.wu;
    
    public class EnglishNoteBook extends NoteBook {
        private static final String TYPE = "英语本";
        private String content;
    
        public void writeContent(String content){
            this.content = content;
        }
        public String getContent(){
            return "内容为:" + content;
        }
        public String getDescription(){
            return "这是一个英语本";
        }
    }
    
    
    package com.wu;
    
    public class Client {
        public static void main(String[] args) {
            // 创建书店对象
            BookStore bookStore = new BookStore();
            // 销售数学本
            MathBookFactory mathBookFactory = new MathBookFactory();
            bookStore.setFactory(mathBookFactory);
            NoteBook noteBook = bookStore.sellBook();
            System.out.println(((MathNoteBook) noteBook).getDescription());
            // 销售英语本
            EnglishBookFactory englishBookFactory = new EnglishBookFactory();
            bookStore.setFactory(englishBookFactory);
            noteBook = bookStore.sellBook();
            System.out.println(((EnglishNoteBook) noteBook).getDescription());
        }
    }
    
    

    抽象工厂模式

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

    概念
    是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
    抽象工厂模式时工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

    抽象工厂模式主要角色

    • 抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品
    • 具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建
    • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
    • 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系

    优缺点

    • 优点:
      当一个产品族中的多个对象设计成一起工作时,它能保证客户端始终使用一个产品族中的对象
    • 缺点:
      当产品族中需要增加一个新产品时,所有工厂类都需要进行修改

    使用场景

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

    UML类图:

    MathBookFactory +createNoteBook() : NoteBook +createTextBook() : TextBook «interface» BookFactory +createNoteBook() : NoteBook +createTextBook() : TextBook EnglishBookFactory +createNoteBook() : NoteBook +createTextBook() : TextBook EnglishTextBook +description() : void TextBook +description() : void MathTextBook +description() : void MathNoteBook +description() : void NoteBook +description() : void EnglishNoteBook +description() : void

    代码如下:

    package com.wu;
    
    public interface BookFactory {
        // 生产本子的功能
        NoteBook createNoteBook();
        // 生产教科书的功能
        TextBook createTextBook();
    }
    
    
    package com.wu;
    
    public class Client {
        public static void main(String[] args) {
            MathBookFactory mathBookFactory = new MathBookFactory();
            // 创建数学教科书
            TextBook mathTextBook = mathBookFactory.createTextBook();
            mathTextBook.description();
            // 创建数学本子
            NoteBook mathNoteBook = mathBookFactory.createNoteBook();
            mathNoteBook.description();
    
            EnglishBookFactory englishBookFactory = new EnglishBookFactory();
            // 创建英语本子
            NoteBook englishNoteBook = englishBookFactory.createNoteBook();
            englishNoteBook.description();
            // 创建英语教科书
            TextBook englishTextBook = englishBookFactory.createTextBook();
            englishTextBook.description();
        }
    }
    
    
    package com.wu;
    
    public class EnglishBookFactory implements BookFactory{
    
        @Override
        public NoteBook createNoteBook() {
            return new EnglishNoteBook();
        }
    
        @Override
        public TextBook createTextBook() {
            return new EnglishTextBook();
        }
    }
    
    
    package com.wu;
    
    public class EnglishNoteBook extends NoteBook {
        @Override
        public void description(){
            System.out.println("这是一个英语本… ");
        }
    }
    
    
    package com.wu;
    
    public class EnglishTextBook extends TextBook{
    
        @Override
        public void description() {
            System.out.println("这是一本英语教科书… ");
        }
    }
    
    
    package com.wu;
    
    public class MathBookFactory implements BookFactory{
    
        @Override
        public NoteBook createNoteBook() {
            return new MathNoteBook();
        }
    
        @Override
        public TextBook createTextBook() {
            return new MathTextBook();
        }
    }
    
    
    package com.wu;
    
    public class MathNoteBook extends NoteBook {
        @Override
        public void  description(){
            System.out.println("这是一个数学本… ");
        }
    }
    
    
    package com.wu;
    
    public class MathTextBook extends TextBook{
        @Override
        public void description() {
            System.out.println("这是一本数学教科书… ");
        }
    }
    
    
    package com.wu;
    
    public abstract class NoteBook {
        public abstract void description();
    }
    
    
    package com.wu;
    
    public abstract class TextBook {
        public abstract void description();
    }
    
    
    展开全文
  • 创建模式 单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式

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

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

    一、单例模式

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

    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. 一个对象多个修改者的场景
        一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
    展开全文
  • 设计模式创建模式

    千次阅读 2019-03-31 12:17:53
    设计模式创建模式:单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式

    一、简介

    创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。

    创建型模式(Creational Pattern)

    • 单例模式 Singleton Pattern: 单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
      使用频率:★★★★☆

    • 简单工厂模式 Simple Factory Pattern: 又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
      使用频率:★★★☆☆

    • 工厂方法模式 Factory Method Pattern: 是一种常用的类创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。
      使用频率:★★★★★

    • 抽象工厂模式 Abstract Factory Pattern: 是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。
      使用频率:★★★★★

    • 原型模式 Prototype Pattern: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
      使用频率:★★★☆☆

    • 建造者模式 Builder Pattern: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
      使用频率:★★☆☆☆

    二、单例模式

    2.1、饿汉式

    /**
     * 单例模式(饿汉式)
     * 线程安全,没有加锁,执行效率会提高。
     * 类加载时就初始化,浪费内存,容易产生垃圾对象
     * <p>
     * 单例类使用了final修饰,防止被继承
     * 这种写法比较简单,就是在类装载的时候就完成实例化。instance作为类变量,在类初始化过程中,会被收集进<clinit>()方法中,该方法会保障同步,从而避免了线程同步问题。
     * 在类装载的时候就完成实例化,若从未使用过这个实例,则会造成内存的浪费。
     */
    public final class SingleObject1 {
        //创建 SingleObject1 的一个对象
        private static SingleObject1 instance = new SingleObject1();
        //私有化构造函数,这样该类就不会被实例化
        private SingleObject1() {}
        //获取唯一可用的对象
        public static SingleObject1 getInstance() {
            return instance;
        }
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用
    SingleObject1.getInstance().say();//Hello
    

    2.2、懒汉式,线程不安全

    /**
     * 单例模式(懒汉式,线程不安全)
     * 线程不安全,没有加锁。
     * 此方式在确定是单线程的情况下,可以保证创建的对象唯一性
     */
    public final class SingleObject2 {
        //创建 SingleObject1 的一个对象
        private static SingleObject2 instance;
        //私有化构造函数,这样该类就不会被实例化
        private SingleObject2() {}
        //获取唯一可用的对象
        public static SingleObject2 getInstance() {
            if (instance == null) {
                instance = new SingleObject2();
            }
            return instance;
        }
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用
    SingleObject2.getInstance().say();//Hello
    

    2.3、懒汉式,线程安全

    /**
     * 单例模式(懒汉式,线程安全)
     * 线程安全,加锁,执行效率低
     */
    public final class SingleObject3 {
        //创建 SingleObject1 的一个对象
        private static SingleObject3 instance;
        //私有化构造函数,这样该类就不会被实例化
        private SingleObject3() {}
        //获取唯一可用的对象
        public synchronized static  SingleObject3 getInstance() {
            if (instance == null) {
                instance = new SingleObject3();
            }
            return instance;
        }
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用
    SingleObject3.getInstance().say();//Hello
    

    2.4、双检锁/双重校验锁

    /**
     * 单例模式(双检锁/双重校验锁)
     * 线程安全
     * 种方式采用双锁机制,安全且在多线程情况下能保持高性能
     */
    public final class SingleObject4 {
        //创建 SingleObject1 的一个对象
        private volatile static SingleObject4 instance;
        //私有化构造函数,这样该类就不会被实例化
        private SingleObject4() {}
        //获取唯一可用的对象
        public static SingleObject4 getInstance() {
            if (instance == null) {
                synchronized (SingleObject4.class) {
                    if (instance == null) {
                        instance = new SingleObject4();
                    }
                }
            }
            return instance;
        }
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用
    SingleObject4.getInstance().say();//Hello
    

    2.5、静态内部类方式

    /**
     * 单例模式(静态内部类实现模式)
     * 线程安全,调用效率高,可以延时加载
     * 这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。
     * 这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
     * 这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,
     * <p>
     * 静态内部类方式是最好也是最常用的几种实现单例模式的方式之一
     */
    public final class SingleObject5 {
    
        private static class SingleObject5Holder {
            private static final SingleObject5 instance = new SingleObject5();
        }
        //私有化构造函数,这样该类就不会被实例化
        private SingleObject5() {}
        //获取唯一可用的对象
        public static SingleObject5 getInstance() {
            return SingleObject5Holder.instance;
        }
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用单例
    SingleObject5.getInstance().say();//Hello
    

    2.6、枚举方式

    /**
     * 单例模式(枚举方式,Android不推荐)
     * 线程安全,调用效率高,不能延时加载,可以防止反射和反序列化调用
     * 这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
     * 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,
     * 防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
     * 不能通过 reflection attack 来调用私有构造方法。
     *
     * 枚举实现单例,不推荐在Android平台使用,因为内存消耗会其他方式多一些,Android官方也不推荐枚举,
     * Android平台推荐双重校验或者静态内部类单例,现在的Android开发环境jdk一般都大于1.5了。所以volatile的问题不必担心。
     * Java平台开发的Effective Java一书中推荐使用枚举实现单例,可以保证效率,而且还能解决反序列化创建新对象的问题。
     */
    public  enum SingleObject6 {
        INSTANCE;
    
        public void say() {
            System.out.println("Hello");
        }
    }
    
    ……
    //调用单例
    SingleObject6.INSTANCE.say();//Hello
    

    三、简单工厂模式

    3.1、定义接口

    定义人接口,吃的动作方法.

    public interface Human {
      	//吃动作
        void eat();
    }
    

    3.2、定义具体实现

    定义中国人.

    public class Chinese implements Human {
        @Override
        public void eat() {
            System.out.println("中国人吃饭");
        }
    }
    

    定义美国人.

    public class American implements Human {
        @Override
        public void eat() {
            System.out.println("美国人吃饭");
        }
    }
    

    3.3、定义工厂类

    方式一: 通过type创建工厂类

    public class HumanFactory {
        public static String CHINESE_HUMAN = "CHINESE_HUMAN";
        public static String AMERICAN_HUMAN = "AMERICAN_HUMAN";
    
        /**
         * 创建人类工厂方法
         * @param type {@link #CHINESE_HUMAN}、{@link #AMERICAN_HUMAN}
         * @return 人类
         */
        public Human createHuman(@NotNull String type) {
            if (type.equals(CHINESE_HUMAN)) {
                return new Chinese();
            } else if (type.equals(AMERICAN_HUMAN)) {
                return new American();
            }
            return null;
        }
    }
    

    方式二: 通过java反射方式创建工厂类

    public class HumanFactory2 {
        /**
         * 创建人类工厂方法
         * @param c 中国人、美国人
         * @param <T> 
         * @return 人类
         */
        public <T extends Human> T  createHuman(Class<T> c) {
            T t=null;
            try {
                t = (T) Class.forName(c.getName()).newInstance();
            } catch (InstantiationException e) {
                System.out.println("不支持抽象类或接口");
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                System.out.println("没有足够权限,即不能访问私有对象");
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                System.out.println("类不存在");
                e.printStackTrace();
            }
            return t;
        }
    }
    

    3.5、使用简单工厂模式

    public static void main(String[] args) {
        //----------------------方式一------------------------------
        //创建工厂类
        HumanFactory humanFactory=new HumanFactory();
        //创建美国人
        Human human1 = humanFactory.createHuman(HumanFactory.AMERICAN_HUMAN);
        human1.eat();//美国人吃饭
        //创建中国人
        Human human2 = humanFactory.createHuman(HumanFactory.CHINESE_HUMAN);
        human2.eat();//中国人吃饭
        
        //----------------------方式二------------------------------
         HumanFactory2 humanFactory2 = new HumanFactory2();
         Human human3 = humanFactory2.createHuman(American.class);
         human3.eat();//美国人吃饭
         Human human4 = humanFactory2.createHuman(Chinese.class);
         human4.eat();//中国人吃饭
    }
    

    四、工厂方法模式

    4.1、定义接口

    定义人接口,吃的动作方法.

    public interface Human {
      	//吃动作
        void eat();
    }
    

    定义工厂类接口

    //工厂接口类
    public interface Factory {
        //创建人类
        Human createHuman();
    }
    

    4.2、定义具体实现

    定义中国人.

    public class Chinese implements Human {
        @Override
        public void eat() {
            System.out.println("中国人吃饭");
        }
    }
    

    定义美国人.

    public class American implements Human {
        @Override
        public void eat() {
            System.out.println("美国人吃饭");
        }
    }
    

    定义中国人工厂类

    //中国人工厂类
    public class ChineseFactory implements Factory {
        @Override
        public Human createHuman() {
            return new Chinese();
        }
    }
    

    定义美国人工厂类

    //美国人工厂类
    public class AmericanFactory implements Factory{
        @Override
        public Human createHuman() {
            return new American();
        }
    }
    

    4.3、使用工厂方法模式

    public static void main(String[] args) {
        Factory factory1 = new AmericanFactory();
        Human human1 = factory1.createHuman();
        human1.eat();//美国人吃饭
    
        Factory factory2 = new ChineseFactory();
        Human human2 = factory2.createHuman();
        human2.eat();//中国人吃饭
    }
    

    五、抽象工厂模式

    5.1、定义接口

    定义人接口,吃的动作方法.

    public interface Human {
      	//吃动作
        void eat();
    }
    

    定义水果接口

    //水果接口
    public interface Fruits {
        //水果名称
        String name();
    }
    
    

    定义工厂接口,每个工厂都有制造人和苹果方法

    //工厂接口
    public interface Factory {
        //创建人类
        Human createHuman();
        //创建水果
        Fruits createFruits();
    }
    

    5.2、定义具体实现

    定义中国人

    public class Chinese implements Human {
        @Override
        public void eat() {
            System.out.println("中国人吃饭");
        }
    }
    

    定义美国人

    public class American implements Human {
        @Override
        public void eat() {
            System.out.println("美国人吃饭");
        }
    }
    

    定义苹果

    //苹果实体
    public class Apple implements Fruits{
        @Override
        public String name() {
            System.out.println("苹果");
            return "苹果";
        }
    }
    

    定义葡萄

    //葡萄实体
    public class Grape implements Fruits {
        @Override
        public String name() {
            System.out.println("葡萄");
            return "葡萄";
        }
    }
    

    定义制造中国人和苹果的工厂

    //制造工厂A 制造中国人和苹果
    public class CreateFactoryA  implements Factory{
        @Override
        public Human createHuman() {
            return new Chinese();
        }
        @Override
        public Fruits createFruits() {
            return new Apple();
        }
    }
    

    定义制造美国人和葡萄的工厂

    //制造工厂B 制造美国人和葡萄
    public class CreateFactoryB implements Factory{
        @Override
        public Human createHuman() {
            return new American();
        }
        @Override
        public Fruits createFruits() {
            return new Grape();
        }
    }
    
    

    5.3、使用抽象工厂模式

      public static void main(String[] args) {
            Factory factory1=new CreateFactoryA();
            Human human = factory1.createHuman();
            Fruits fruits = factory1.createFruits();
            human.eat();//中国人吃饭
            fruits.name();//苹果
    
            Factory factory2=new CreateFactoryB();
            Human human2 = factory2.createHuman();
            Fruits fruits2 = factory2.createFruits();
            human2.eat();//美国人吃饭
            fruits2.name();//葡萄
        }
    

    六、原型模式

    原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

    6.1、浅拷贝实现原型模式

    新建Book类实现Cloneable接口,复写clone方法

    //书原型(浅拷贝)
    public class Book implements Cloneable {
        //书名
        private String title;
        //书页数
        private ArrayList<String> page = new ArrayList<String>();
    
        public Book() {
            //一个实现了Cloneable并重写了clone方法的类,通过clone得到对象构造函数是不会被执行
            System.out.println("构造函数被执行了");
        }
    
        @Override
        protected Book clone() {
            try {
                return (Book) super.clone();
            } catch (CloneNotSupportedException e) {
                //异常处理
                e.printStackTrace();
                return null;
            }
        }
    
        public String getTitle() {return title;}
    
        public void setTitle(String title) {this.title = title;}
    
        public List<String> getPage() {return page;}
    
        public void addPage(String page) {this.page.add(page);}
    
        @Override
        public String toString() {
            return "Book{" +"title='" + title + '\'' +", page=" + page +'}';
        }
    }
    

    测试原型模式

    //浅拷贝测试
    Book book = new Book();
    book.setTitle("Java");
    book.addPage("Java第1章");
    System.out.println(book.toString());//Book{title='Java', page=[Java第1章]}
    
    Book cloneBook = book.clone();
    cloneBook.setTitle("Android");
    cloneBook.addPage("Android第1章");
    System.out.println(cloneBook.toString());//Book{title='Android', page=[Java第1章, Android第1章]}
    
    // 再次打印原始书本发现原书信息被修改(因为Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、集合、容器对象、引用对象等都不会拷贝,需要使用深拷贝解决)
    System.out.println(book.toString());//Book{title='Java', page=[Java第1章, Android第1章]}
    

    6.2、深拷贝实现原型模式

    新建Book类实现Cloneable接口,复写clone方法,因为Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、集合、容器对象、引用对象等都不会拷贝,需要将page进行深度拷贝.

    //书原型(深拷贝)
    public class Book2 implements Cloneable {
        //书名
        private String title;
        //书页数
        private ArrayList<String> page = new ArrayList<String>();
    
        @Override
        protected Book2 clone() {
            try {
                Book2 book2 = (Book2) super.clone();
                book2.page= (ArrayList<String>) this.page.clone();
                return book2;
            } catch (CloneNotSupportedException e) {
                //异常处理
                e.printStackTrace();
                return null;
            }
        }
    
        public String getTitle() {return title;}
    
        public void setTitle(String title) {this.title = title;}
    
        public List<String> getPage() {return page;}
    
        public void addPage(String page) {this.page.add(page);}
    
        @Override
        public String toString() {
            return "Book{" +"title='" + title + '\'' +", page=" + page +'}';
        }
    }
    

    测试原型模式

    //深拷贝测试
    Book2 book2 = new Book2();
    book2.setTitle("Java");
    book2.addPage("Java第1章");
    System.out.println(book2.toString());//Book{title='Java', page=[Java第1章]}
    
    Book2 cloneBook2 = book2.clone();
    cloneBook2.setTitle("Android");
    cloneBook2.addPage("Android第1章");
    System.out.println(cloneBook2.toString());//Book{title='Android', page=[Java第1章, Android第1章]}
    
    // 再次打印原始书本发现原书没有被改变
    System.out.println(book2.toString());//Book{title='Java', page=[Java第1章]}
    

    6.3、使用原型模式注意事项

    • 构造函数不会被执行

      通过clone复制得到对象,该对象构造函数是不会被执行的。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不 会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。在单例模式中,只要将构造方法的访问权限设置为 private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的。

    • 浅拷贝和深拷贝

      clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。在开发中,为减少错误,建议在使用原型模式时尽量使用深拷贝,避免操作副本时影响原始对象的问题。如果是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。

    • clone与final

      要使用clone方法,类的成员变量上不要增加final关键字,因为final类型是不允许重赋值的。

    七、建造者模式

    建造者模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    7.1、建造者模式的定义

    定义产品类

    //具体产品类
    public class Product {
        private String name;
        private String desc;
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public String getDesc() {return desc;}
        public void setDesc(String desc) {this.desc = desc;}
        @Override
        public String toString() {
            return "Product{" +"name='" + name + '\'' +", desc='" + desc + '\'' +'}';
        }
    }
    

    定义抽象建造者

    //定义抽象建造者
    public abstract class Builder {
        //设置产品名称
        abstract void setName(String name);
        //设置产品描述
        abstract void setDesc(String desc);
        //构建产品
        abstract Product builderProduct();
    }
    

    定义具体建造者

    //定义具体建造者
    public class ConcreteProduct extends Builder {
        private final Product product;
        public ConcreteProduct() { product = new Product();}
        @Override
        void setName(String name) {
            product.setName(name);
        }
        @Override
        void setDesc(String desc) {
            product.setDesc(desc);
        }
        @Override
        Product builderProduct() {
            return product;
        }
    }
    

    定义指挥者类

    //定义指挥者类
    public class Director {
        private final ConcreteProduct concreteProduct;
        public Director() {
            concreteProduct = new ConcreteProduct();
        }
        public Product getProduct(String name,String desc){
            concreteProduct.setName(name);
            concreteProduct.setDesc(desc);
           return concreteProduct.builderProduct();
        }
    }
    

    使用建造者模式

    public static void main(String[] args) {
            Director director = new Director();
            Product product = director.getProduct("产品A", "A 的描述");
            System.out.println(product);//Product{name='产品A', desc='A 的描述'}
        }
    

    7.2、Android中建造者实现

    Android中的AlertDialog.Builder就是使用了Builder模式来构建AlertDialog的。

    Android AlertDialog简单构建与使用

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);//创建一个Builder对象
      builder.setIcon(R.drawable.icon);
      builder.setTitle("标题");
      builder.setMessage("内容");
      builder.setPositiveButton("确定", null);
      AlertDialog alertDialog = builder.create();//创建AlertDialog对象
      alertDialog.show();//显示AlertDialog
    

    通过Builder对象来构建Icon、Title、Message、按钮监听等,将AlertDialog的构建过程和细节隐藏了起来。

    AlertDialog部分源码:

    public class AlertDialog extends AppCompatDialog implements DialogInterface {
        final AlertController mAlert;
        protected AlertDialog(@NonNull Context context) {
            this(context, 0);
        }
        ……
        public static class Builder {
            private final AlertController.AlertParams P;//存放构建时设置的参数
            ……
            public Builder(@NonNull Context context) {
                this(context, resolveDialogTheme(context, 0));
            }
    		……
         	public Builder(@NonNull Context context) {//构建Builder
                this(context, resolveDialogTheme(context, 0));
            }
            ……
            public Builder setTitle(@Nullable CharSequence title) {//设置标题
                P.mTitle = title;
                return this;
            }
            ……
            public Builder setMessage(@Nullable CharSequence message) {//设置内容
                P.mMessage = message;
                return this;
            }
    		……
            public Builder setIcon(@DrawableRes int iconId) {//设置icon
                P.mIconId = iconId;
                return this;
            }
    		……
            public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {//设置按钮和监听
                P.mPositiveButtonText = text;
                P.mPositiveButtonListener = listener;
                return this;
            }
    		……
            public AlertDialog create() {//构建AlertDialog
                final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
                P.apply(dialog.mAlert);//将构建时参数通过AlertController运用到AlertDialog上
                dialog.setCancelable(P.mCancelable);
                if (P.mCancelable) {dialog.setCanceledOnTouchOutside(true);}
                dialog.setOnCancelListener(P.mOnCancelListener);
                dialog.setOnDismissListener(P.mOnDismissListener);
                if (P.mOnKeyListener != null) {dialog.setOnKeyListener(P.mOnKeyListener);}
                return dialog;
            }
    		……
        }
    }
    

    AlertController部分源码:

    class AlertController { 
    	public static class AlertParams {
      	……
            public void apply(AlertController dialog) {//将构建时参数通过AlertController运用到AlertDialog上
                if (mCustomTitleView != null) {
                    dialog.setCustomTitle(mCustomTitleView);
                } else {
                    if (mTitle != null) {
                        dialog.setTitle(mTitle);
                    }
                    if (mIcon != null) {
                        dialog.setIcon(mIcon);
                    }
                    if (mIconId != 0) {
                        dialog.setIcon(mIconId);
                    }
                    if (mIconAttrId != 0) {
                        dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
                    }
                }
                if (mMessage != null) {
                    dialog.setMessage(mMessage);
                }
                if (mPositiveButtonText != null || mPositiveButtonIcon != null) {
                    dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                            mPositiveButtonListener, null, mPositiveButtonIcon);
                }
                ……
    

    Android中 AlertDialog使用是通过AlertDialog.Builder设置各种属性后(如:setTitle()),这些属性信息会保存在P(AlertController.AlertParams)变量中,调用create()即可返回一个AlertDialog对象,create()方法中P.apply(dialog.mAlert)是将构建时设置的参数通过AlertController运用到AlertDialog上,最后调用AlertDialog中的show()显示对话框。AlertDialog通过builder模式隐藏了这种复杂的构建过程,只需几行简单的代码就把AlertDialog给展示出来了,AlertDialogbuilder中并没有抽象建造者(Builder)、Director(指挥者类)等角色。AlertDialog.Builder同时扮演了BuilderConcreteBuilderDirector等角色,这是Android源码中使用构建者模式的一种简化。

    展开全文
  • 题目:在某OA系统中,用户可以创建工作周报,由于某些岗位周周工作存在重复性,因此可以通过复制原有工作周报并进行局部修改来快速新建工作周报。 类图 package cn.factory4; public class ...
  • 创建模式——工厂方法模式

    千次阅读 2020-07-10 08:22:13
    在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被...
  • 工厂模式创建对象的最佳方式)

    千次阅读 2021-07-14 10:01:02
    这种类型的设计模式属于创建模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 工厂模式具体包括了简单工厂、...
  • 设计模式 ① — 创建模式

    千次阅读 2018-06-07 11:24:26
    抽象工厂模式(Abstract Factory): 解决一系列相互依赖对象的创建工作。创建者模式(Builder):解决“一些复杂对象”的创建工作。原型模式(Prototype):解决某些结构复杂的对象的创建工作。单例模式(Singleton...
  • 以形成良好的软件体系结构,主要的方式是使用继承关系来组织各个类,一个最容易的例子就是如何用多个继承组织两个以上的类,结果产生的类结合了父类所有的属性,结构型模式特别适用于和独立的类库一起工作。...
  • 这种类型的设计模式属于创建模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,...
  • 创建模式——抽象工厂模式

    千次阅读 2018-03-10 10:40:27
    这种类型的设计模式属于创建模式,它提供了一种创建对象的最佳方式。 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。 介绍 意图...
  • 工厂除了将创建和使用对象分离,还有一个作用就是可以屏蔽一些创建对象后初始化的事情,如果直接反射具体的产品对象,那么反射对象后,需要每次都做初始化的工作,而放在工厂中,就不需要每次都初始化了 工厂模式优...
  • 工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂...当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,保证客户端始终只使用同一个产品族
  • 创建模式之建造者模式——链式调用

    万次阅读 多人点赞 2021-09-29 11:06:07
    学设计模式有什么用?
  • 实验项目二: 创建型设计模式实验 (1)实验目的与原理 ①结合实例,熟练绘制创建型设计模式结构图。 ②结合实例,熟练使用Java面向对象编程语言实现创建型设计模式。 ③通过编程实践,理解每一种创建型设计模式的概念...
  • 设计模式--六种创建模式

    千次阅读 热门讨论 2017-04-13 16:58:25
     每几种模式之间都有一定的联系,从中发现它们的相同点和不同点,研究发生改变的节点,这就是本篇博客所要说明的创建型设计模式之间的联系。它们包括:简单工厂模式、单例模式、工厂方法模式、抽象工厂模式、建造者...
  • 虽然我家大业大,但也耗不住我这么折腾呢,于是我决定找份工作好好磨练下自己,为爱找份工作,为爱加上期限 – 爱你一万年。 找工作不得写简历吗,我就写呀写呀… 为了提高我投简历的准确性,我觉得简历要写的多样...
  • 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责...
  • 创建模式之原型模式——深拷贝和浅拷贝

    万次阅读 多人点赞 2021-09-22 09:56:39
    迈过数据结构和算法这道坎 《从实战学python》——Python的爬虫,自动化,AI等实战应用 点击跳转到文末领取粉丝福利 哈喽,大家好,我是一条~ 之前的《白话设计模式》因为工作被搁置,如今再次启航,并搭配框架源码...
  • 工厂模式的定义:定义一个创建对象的工厂接口,将对象的实际创建工作推迟到具体子工厂类当中。 这满足创建型模式中所要求的“创建与使用相分离”的特点。 按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别...
  • wifi的几种工作模式

    万次阅读 2018-12-11 23:49:20
    WIFI配置具体的模式主要有以下这几种:STA模式、AccessPoint模式、Monitor模式、Ad-hoc(IBSS)模式、WDS模式、Mesh模式。 第一种:STA模式  任何一种无线网卡都可以...这种模式下,wifi工作于从模式 第二种:Ac...
  •  每几种模式之间都有一定的联系,从中发现它们的相同点和不同点,研究发生改变的节点,这就是本篇博客所要说明的创建型设计模式之间的联系。它们包括:简单工厂模式、单例模式、工厂方法模式、抽象工厂模式、建造者...
  • FTP服务器的两种工作模式

    千次阅读 2020-08-18 11:21:48
    FTP协议: FTP(File transfer Protocol)是一种在互联网中进行文件传输的协议,基于客户端/服务器模式,默认使用20、21号端口, ...Ftp有两种工作模式: 主动模式(PORT):服务器主动向客户端发起连接请求. 被动模
  • 设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟的解决方案 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性 单例设计模式 目的—— ...
  • Java设计模式_(创建型)_原型模式

    万次阅读 2017-09-19 17:19:13
    引用百科:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。Prototype原型模式是一种创建型设计模式,Prototype模式允许一...解决什么问题:它主要面对的问题是:“某些结构复杂的对象”的创建工作
  • 创建模式——建造者模式

    千次阅读 2018-03-10 11:30:47
    这种类型的设计模式属于创建模式,它提供了一种创建对象的最佳方式。 一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。 介绍 意图 将一个复杂的构建与其表示相分离,使得同样...
  • Java常见设计模式总结

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

    万次阅读 2016-04-30 17:26:47
    创建模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:...
  • Java设计模式_(创建型)_建造者模式

    万次阅读 2017-09-20 16:40:12
    引用百科 建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。实用范围1 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。2 当构造...
  • RabbitMQ的七种工作模式-简单模式(一)

    万次阅读 2020-09-25 10:04:31
    在学习RabbitMQ的工作模式之前,必须先了解Exchange的类型,因为工作模式与交换机类型的基本对应的, 1.Direct:直接交换机通过消息上的路由键直接对消息进行分发,相当于精确匹配,一对一 2.Topic:这个交换机会将...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,198,546
精华内容 479,418
关键字:

创建工作模式