软件设计模式的学习(以Java为例)
文章目录
- 软件设计模式的学习(以Java为例)
- 一、任务要求
- 二、任务过程
- 1.单例模式
- (一)什么是单例模式
- (二)单例模式的实现方法
- 懒汉模式
- 饥汉模式
- 饱汉模式
- 双重锁模式
- (三)单例模式优缺点
- 优点
- 缺点
- 2.工厂模式
- (一)什么是工厂模式
- (二)工厂模式的实现方法
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- (三)工厂模式的优缺点
- 优点
- 缺点
一、任务要求
掌握“单例模型”和“工厂模式”(又分为简单工厂模型、工厂方法模型、抽象工厂模式)的概念和优缺点。调通例子代码。
二、任务过程
1.单例模式
(一)什么是单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
(二)单例模式的实现方法
常见的实现方式有:懒汉模式、饥汉模式、饱汉模式等方式实现,那我们我们紧接着就具体的一个一个的来看看他们的实现
懒汉模式
所谓懒汉模式,就是像一个懒汉一样,需要用到创建实例了程序再去创建实例,不需要创建实例程序就“懒得”去创建实例,这是一种时间换空间的做法,这体现了“懒汉的本性”。通过代码可以看出,懒汉单例模式在第一次调用 getInstance 方法时,实例化 LazySingleton 对象,在类加载时并不自行实例化,这种技术称为延迟加载技术(Lazy Load),即在需要的时候进行加载实例。
代码如下
package com.design.singleton;
/**
* 懒汉单例模式,线程不安全
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){
}
public static LazySingleton getInstance(){
if (lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
饥汉模式
所谓饥汉模式,个人理解就是一种程序设计实现的形象的说法,项目中经常有这样的场景:程序启动时,有很多耗时的操作,比如加载图片,加载文件等等,而友好的界面应该是让主界面加载进来,这些耗时费劲的操作放在后台的线程中去执行,完全不影响主界面的加载速度。所以软件设计人员就想到了在程序启动时将这些耗时的操作放在线程,故而把这种初始化加载的方式形象的比作:“饥汉模式”。
代码如下
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
cvIdentify::GetInstance();//饥汉模式初始化
AutoTestUi w;
w.show();
return a.exec();
}
饱汉模式
不是线程安全的,因为是在需要的时候才会产生实例对象,生产之前会判断对象引用是否为空,这里,如果多个线程同时进入判断,就会生成多个实例对象,这是不符合单例的思想的。所以饱汉模式为了保证线程安全,就用synchronized关键字标识了方法。之所以被称为“饱汉”,因为它很饱,不急着生产实例,在需要的时候才会生产。
代码如下
public class SingletonPattern {//单例设计模式中的饱汉式
private SingletonPattern(){}
private static SingletonPattern instance=null;
public static synchronized SingletonPattern getInstance() {
if(instance==null){
instance=new SingletonPattern();
}
return instance;
}
}
双重锁模式
是饱汉模式的优化,进行双重判断,当已经创建过实例对象后就无需加锁,提高效率。也是一种推荐使用的方式。
代码如下
public class Singleton3 {
private static Singleton3 singleton;
private Singleton3(){
}
public static Singleton3 getInstance(){
if(singleton == null){
synchronized(Singleton3.class){
if(singleton == null){
singleton = new Singleton3();
}
}
}
return singleton;
}
}
(三)单例模式优缺点
优点
实例控制:
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
灵活性:
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点
开销:
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
可能的开发混淆:
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
对象生存期:
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
2.工厂模式
(一)什么是工厂模式
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
(二)工厂模式的实现方法
简单工厂模式
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
结构图如下
代码如下
public class SimpleFactoryPattern {
public static void main(String[] args) {
Product product = SimpleFactory.makeProduct(2);
product.show();
}
//抽象产品
public interface Product {
void show();
}
//具体产品:ProductA
static class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1显示...");
}
}
//具体产品:ProductB
static class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2显示...");
}
}
//具体产品:ProductC
static class ConcreteProduct3 implements Product {
@Override
public void show() {
System.out.println("具体产品3显示...");
}
}
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();
case Const.PRODUCT_C:
return new ConcreteProduct3();
}
return null;
}
}
}
工厂方法模式
工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品。
结构图如下
代码如下
/**
* @author hz
* @version 1.0
*/
public class AbstractFactoryTest {
public static void main(String[] args) {
try {
Product a;
AbstractFactory af;
af = (AbstractFactory) ReadXML.getObject();
//抽象工厂内容放入到外部配置文件xml/properties等文件中,通过I/O流加载从而创建出抽象工厂
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.*;
/**
* @author hz
* @version 1.0
*/
public class ReadXML {
//该方法用于从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;
}
}
}
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)隶属于设计模式中的创建型模式,用于产品族的构建。抽象工厂是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
结构图如下
代码如下
//具体类的抽象接口
public interface Shape {
//接口方法
}
//具体类Circle
public class Circle implements Shape {
//接口方法实现
}
//具体类红色圆
public class RedCircle implements Shape {
//接口方法实现
}
//...各种颜色的圆...
//具体类Triangle
public class Triangle implements Shape {
//接口方法实现
}
//具体类红色Triangle
public class RedTriangle implements Shape {
//接口方法实现
}
//...各种颜色的Triangle...
//工厂接口
public interface ShapeFactory {
Shape getShape();
}
//CircleFactory
public class CircleFactory implements ShapeFactory {
//返回实例
}
//RedCircleFactory
public class RedCircleFactory implements ShapeFactory {
//返回实例
}
//...各种颜色的Circle的工厂...
//TriangleFactory
public class TriangleFactory implements ShapeFactory {
//返回实例
}
//RedTriangleFactory
public class RedTriangleFactory implements ShapeFactory {
//返回实例
}
//...各种颜色的Triangle的工厂...
(三)工厂模式的优缺点
优点
分离了具体的类。客户通过抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中。
易于交换产品系列。一个具体工厂类只在初始化时出现一次,这使得改变一个应用的具体工厂变得很容易,只需改变具体的工厂即可使用不同的产品配置。
有利于产品的一致性。当一个系列的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要,而抽象工厂很容易实现这一点。
缺点
难以支持新种类的产品。因为抽象工厂接口确定了可以被创建的产品集合,所以难以扩展抽象工厂以生产新种类的产品。