上次了解了设计模式的几个设计原则,现在来看下几个常见的创建型设计模式,主要有以下几个
1.简单工厂模式
简单工厂模式就是定义一个工厂类,它可以根据参数的不同返回不同的事例,被定义的事例大多都有共同的父类。
class Chart { private String type; //图表类型 public Chart(Object[][] data, String type) { this.type = type; if (type.equalsIgnoreCase("histogram")) { //初始化柱状图 } else if (type.equalsIgnoreCase("pie")) { //初始化饼状图 } else if (type.equalsIgnoreCase("line")) { //初始化折线图 } } public void display() { if (this.type.equalsIgnoreCase("histogram")) { //显示柱状图 } else if (this.type.equalsIgnoreCase("pie")) { //显示饼状图 } else if (this.type.equalsIgnoreCase("line")) { //显示折线图 } } }
上面就是一个简单工厂模式,不难看出有如下几个缺点:
包含很多if else语句,代码冗长,阅读难度大,维护和测试的难度也大;
chart类将对象的判断、初始化、展示全部放在一个类中,违反了单一职责原则;
如果需要增加新表,需要修改Chart类源代码,不符合开闭原则;
2.工厂方法模式
工厂方法模式:定义一个用于创建对象的接口,让子类决定具体创建哪个对象。
以前面的简单工厂模式为例,需要对简单工厂模式重构的代码进行再次重构。
1.将对象类抽象出一个抽象产品类,可以是抽象类,也可以是接口
interface Chart { public void display(); }
2.具体产品类实现抽象接口类,并实现具体的初始化以及展示方法
//柱状图类:具体产品类 class HistogramChart implements Chart { public HistogramChart() { System.out.println("创建柱状图!"); } public void display() { System.out.println("显示柱状图!"); } }
3.创建抽象工厂类
//抽象工厂类 interface ChartFactory{ public Chart createChart(); }
4.创建具体工厂类
//图表工厂类:具体工厂类 class HistogramChartFactory implements ChartFactory{ @Override public Chart createChart() { Chart chart = new HistogramChart(); return chart; } }
5.客户端直接使用工厂类进行对象的初始化
class Client { public static void main(String args[]) { ChartFactory factory; Chart chart; factory = new HistogramChartFactory(); //可引入配置文件实现 chart = factory.createChart(); chart.display(); } }
6.第五步中判断客户端的参数来进行判断初始化,如果需要增加新的对象,那么需要修改工厂类的源代码,不符合开闭原则,可以通过配置文件进行优化(根据开闭原则的定义,配置文件的修改不算是违背开闭原则)。
在xml配置文件中定义键值对,通过DOM读取文件中的对象名,通过Java反射获取制定的对象事例。
public static Object getBean() { try { //创建DOM文档对象 DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dFactory.newDocumentBuilder(); Document doc; doc = builder.parse(new File("config.xml")); //获取包含类名的文本节点 NodeList nl = doc.getElementsByTagName("className"); Node classNode=nl.item(0).getFirstChild(); String cName=classNode.getNodeValue(); /* 其他工厂模式中使用,使其完全符合开闭原则 //通过类名生成实例对象并将其返回 Class c=Class.forName(cName); Object obj=c.newInstance(); return obj;*/ } catch(Exception e) { e.printStackTrace(); return null; } }
3.抽象工厂模式
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。多个抽象产品类,每个抽象产品可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个你具体工厂类。每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品
1.创建抽象工厂类
//抽象工厂类 interface ChartFactory{ public HistogramChart createHistogramChart(); public PieChart createPieChart(); public LineChart createLineChart(); } ...
2.
//图表工厂类:具体工厂类 class RedChartFactory implements ChartFactory{ @Override public HistogramChart createHistogramChart() { HistogramChart chart = new RedHistogramChart(); return chart; } @Override public PieChart createPieChart() { PieChart chart = new RedPieChart(); return chart; } @Override public LineChart createLineChart() { LineChart chart = new RedLineChart(); return chart; } } ...
它的缺点就是结构复杂,重构工作量大。
4.单例模式
单例模式:确保某一个类只有一个实例,而且自行初始化并向整个系统提供这个实例。单例模式是一种很重要的设计模式,也是老生常谈的了。在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
单例模式的实现步骤:
在getInstance方法中,为了向系统提供唯一的实例,需要先判断实例是否初始化了,如果有则返回,如果没有则初始化并返回。当不同线程同时调用该方法时,两个判断语句都会返回false,并且同时初始化实例,导致系统不止有一个实例,引起异常。因此需要对单例模式进行线程安全操作,常见的解决办法有饿汉式、懒汉式。
在私有静态变量定义的时候进行初始化,这样在类加载的时候就已经创建了单例,只需要在getInstance中返回该单例就可以了。
private static final EagerSingleton instance = new EagerSingleton();
在私有静态变量定义的时候不进行初始化,而是在getInstance方法中进行线程保护,可以为etInstance方法添加 synchronized 修饰符,这样在不同线程同时调用getInstance时,就会依次进行访问。
为getInstance方法添加synchronized修饰符后,每次调用方法都会进行同步锁的判定,会消耗大量的系统资源,因此可以对懒汉式进行优化,去掉getInstance方法的synchronized修饰符,只对方法内的初始化方法进行锁定,这样只有在第一次调用时进行同步锁判定,之后都不会影响性能。
if (instance == null) { synchronized (LazySingleton.class) { instance = new LazySingleton(); } }
5.原型模式
原型模式:使用原型实例创建对象的种类,并且通过拷贝这些原型创建新的对象。
在具体原型类的克隆方法中实例化一个与自身类型相同的对象并将其返回,并将相关的参数传入新创建的对象中。
public Prototype clone() //克隆方法 { Prototype prototype = new ConcretePrototype(); //创建新对象 prototype.setAttr(this.attr); return prototype; }
所有Java类都继承自java.lang.Object,Object类提供了一个clone方法,可以将Java对象复制一份。需要注意的是能够实现克隆的Java类必须实现Cloneable接口,否则会报异常。
克隆方法分为深克隆跟浅克隆,主要区别在于是否支持引用类型的成员变量的复制。
6.建造者模式
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。模式结构图如下:
class Director { private Builder builder; public Director(Builder builder) { this.builder=builder; } public void setBuilder(Builder builder) { this.builder=builer; } //产品构建与组装方法 public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
建造者模式跟抽象工厂模式有点类似,但建造者模式返回一个完整的复杂对象,抽象工程模式返回一系列对象。
原文:https://www.cnblogs.com/yokely/p/13022098.html