Java23种设计模式之创建型模式

学习自http://c.biancheng.net/view/8508.html

设计原则

在这里插入图片描述

创建型模式

  • 特点:将对象的创建与使用分离

单例模式

  • 对象创建型模式

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

  • 目的:节省内存资源、保证数据内容的一致性

  • 特点

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

    • 单例模式可以保证内存里只有一个实例,减少了内存的开销。
    • 可以避免对资源的多重占用。
    • 单例模式设置全局访问点,可以优化和共享资源的访问
  • 单例模式的缺点:

    • 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
    • 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
    • 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
  • 实现方式

懒汉式单例

  • 类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例
  • 若删除代码中的关键字 volatile 和 synchronized会造成线程不安全
  • 缺点:如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源
public class LazySingleton {
    private static volatile LazySingleton instance = null;    //保证 instance 在所有线程中同步
    private LazySingleton() {
    }    //private 避免类在外部被实例化
    public static synchronized LazySingleton getInstance() {
        //getInstance 方法前加同步
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

饿汉式单例

  • 类加载时生成单例

  • 线程安全

public class HungrySingleton {
    private static final HungrySingleton instance = new HungrySingleton();
    private HungrySingleton() {
    }
    public static HungrySingleton getInstance() {
        return instance;
    }
}

原型模式

  • 对象创建型模式

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

  • 优点:

    • Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
    • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
  • 缺点:

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
  • 原型模式包含以下主要角色。

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

    • 深拷贝:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址

      img
    • 浅拷贝:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址

      img
  • //具体原型类
    class Realizetype implements Cloneable {
        Realizetype() {
            System.out.println("具体原型创建成功!");
        }
        public Object clone() throws CloneNotSupportedException {
            System.out.println("具体原型复制成功!");
            return (Realizetype) super.clone();
        }
    }
    //原型模式的测试类
    public class PrototypeTest {
        public static void main(String[] args) throws CloneNotSupportedException {
            Realizetype obj1 = new Realizetype();
            Realizetype obj2 = (Realizetype) obj1.clone();
            System.out.println("obj1==obj2?" + (obj1 == obj2));
        }
    }
    

简单(静态)工厂模式

  • 对象创建模型

  • 优点:

    1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
    2. 客户端无需知道所创建具体产品的类名,只需知道参数即可。
    3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
  • 缺点:

    1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
    2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
    3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂(违背开闭原则)
    4. 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
  • 结构:

    • 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
    • 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
    • 具体产品(ConcreteProduct):是简单工厂模式的创建目标。
  • public class Client {
        public static void main(String[] args) {
        }
        //抽象产品
        public interface Product {
            void show();
        }
        //具体产品:ProductA
        static class ConcreteProduct1 implements Product {
            public void show() {
                System.out.println("具体产品1显示...");
            }
        }
        //具体产品:ProductB
        static class ConcreteProduct2 implements Product {
            public void show() {
                System.out.println("具体产品2显示...");
            }
        }
        final class Const {
            static final int PRODUCT_A = 0;
            static final int PRODUCT_B = 1;
            static final int PRODUCT_C = 2;
        }
        static class SimpleFactory {
            public static Product makeProduct(int kind) {
                switch (kind) {
                    case Const.PRODUCT_A:
                        return new ConcreteProduct1();
                    case Const.PRODUCT_B:
                        return new ConcreteProduct2();
                }
                return null;
            }
        }
    }
    

工厂方法模式

  • 类创建型模式
  • 只考虑生产同等级的产品
  • 实现了接口的类的对象赋给接口,通过该对象去调用方法
  • 优点:
  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
  • 缺点:

    • 类的个数容易过多,增加复杂度
    • 增加了系统的抽象性和理解难度
    • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
  • 结构

    • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
    • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应
  • package FactoryMethod;
    
    public class AbstractFactoryTest {
        public static void main(String[] args) {
            try {
                Product a;
                AbstractFactory af;
                af = (AbstractFactory) ReadXML1.getObject();
                a = af.newProduct();
                a.show();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    //抽象产品:提供了产品的接口
    interface Product {
        public void show();
    }
    
    //具体产品1:实现抽象产品中的抽象方法
    class ConcreteProduct1 implements Product {
        public void show() {
            System.out.println("具体产品1显示...");
        }
    }
    
    //具体产品2:实现抽象产品中的抽象方法
    class ConcreteProduct2 implements Product {
        public void show() {
            System.out.println("具体产品2显示...");
        }
    }
    
    //抽象工厂:提供了厂品的生成方法
    interface AbstractFactory {
        public Product newProduct();
    }
    
    //具体工厂1:实现了厂品的生成方法
    class ConcreteFactory1 implements AbstractFactory {
        public Product newProduct() {
            System.out.println("具体工厂1生成-->具体产品1...");
            return new ConcreteProduct1();
        }
    }
    
    //具体工厂2:实现了厂品的生成方法
    class ConcreteFactory2 implements AbstractFactory {
        public Product newProduct() {
            System.out.println("具体工厂2生成-->具体产品2...");
            return new ConcreteProduct2();
        }
    }
    
    import javax.xml.parsers.*;
    import org.w3c.dom.*;
    import java.io.*;
    class ReadXML1 {
        //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
        public static Object getObject() {
            try {
                //创建文档对象
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = dFactory.newDocumentBuilder();
                Document doc;
                doc = builder.parse(new File("src/FactoryMethod/config1.xml"));
                //获取包含类名的文本节点
                NodeList nl = doc.getElementsByTagName("className");
                Node classNode = nl.item(0).getFirstChild();
                String cName = "FactoryMethod." + classNode.getNodeValue();
                //System.out.println("新类名:"+cName);
                //通过类名生成实例对象并将其返回
                Class<?> c = Class.forName(cName);
                Object obj = c.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

抽象工厂模式

  • 对象创建型模式

  • 抽象工厂模式是工厂方法模式的升级版本,可生产多个等级的产品。

  • 使用抽象工厂模式一般要满足以下条件。

    • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
    • 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
  • 优点

    • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
    • 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
    • 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
  • 缺点

    • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度
  • 与工厂模式大致相同

    (1) 抽象工厂:提供了产品的生成方法。

    interface AbstractFactory {   
    public Product1 newProduct1();   
    public Product2 newProduct2();
    }
    

    (2) 具体工厂:实现了产品的生成方法。

    class ConcreteFactory1 implements AbstractFactory {    
        public Product1 newProduct1() {        
            System.out.println("具体工厂 1 生成-->具体产品 11...");        
            return new ConcreteProduct11();    
        }    
        public Product2 newProduct2() {        
           System.out.println("具体工厂 1 生成-->具体产品 21...");        
           return new ConcreteProduct21();    
        }
    }
    

建造者模式

  • 对象创建型模式

  • 它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的

  • 优点:

    1. 封装性好,构建和表示分离。
    2. 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
    3. 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
  • 缺点:

    1. 产品的组成部分必须相同,这限制了其使用范围。
    2. 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大
  • 应用场景

    • 相同的方法,不同的执行顺序,产生不同的结果。
    • 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
    • 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
    • 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。
  • 建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程

  • (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.setPartB("建造 PartB");    
        }    
        public void buildPartC() {        
            product.setPartC("建造 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();    
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值