计算机软件基础经典例子3

Singleton 单例模式的作用是在软件环境中创建唯一的对象实例。单例
模式的实现要考虑的问题有: (1) GetInstance 方法需返回唯一的对象实例 (2)应付
多线程访问。
A:(3 分)不考虑多线程访问,给出单例模式实现的代码,包括类构造函数代码,
GetInstance 函数代码。
B:(3 分)在多线程的情况下,可能出现多种使得唯一对象实例创建失败的情况。
请阐述其中任意一种情况。
C:(2 分)针对你在 B 中阐述的情况,给出可以避免此多线程问题的代码,并解
释其思路。

抽象工厂模式用于创建属于多个产品层级的一族对象。请回答问题。
A: (2 分)用类图举例说明什么是产品层级。
B: (2 分)用类图举例说明什么是属于多个产品层级的一族对象。
C: (6 分)某移动操作系统软件需要创建 IOS 风格和 WP 风格的两套界面,每套
界面包含控件 Button 和 Scrollbar。请用抽象工厂模式设计该软件。

单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。
许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

img

优点:

在内存中只有一个对象,节省内存空间;

避免频繁的创建销毁对象,可以提高性能;

避免对共享资源的多重占用,简化访问;

为整个系统提供一个全局访问点。

缺点:

不适用于变化频繁的对象;

滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;

如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;

饿汉式单例

// 饿汉式单例
public class Singleton1 {
 
    // 指向自己实例的私有静态引用,主动创建
    private static Singleton1 singleton1 = new Singleton1();
 
    // 私有的构造方法
    private Singleton1(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton1 getSingleton1(){
        return singleton1;
    }
}

优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

**懒汉式 **

// 懒汉式单例
public class Singleton2 {
 
    // 指向自己实例的私有静态引用
    private static Singleton2 singleton2;
 
    // 私有的构造方法
    private Singleton2(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton2 getSingleton2(){
        // 被动创建,在真正需要使用时才去创建
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

这种写法起到了Lazy Loading的效果,但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

双重加锁机制

public class Singleton
    {
        private static Singleton instance;
        //程序运行时创建一个静态只读的进程辅助对象
        private static readonly object syncRoot = new object();
        private Singleton() { }
        public static Singleton GetInstance()
        {
            //先判断是否存在,不存在再加锁处理
            if (instance == null)
            {
                //在同一个时刻加了锁的那部分程序只有一个线程可以进入
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

优点:线程安全;延迟加载;效率较高。

A: 不考虑多线程访问的情况下,单例模式的实现代码如下:

class Singleton {
private:
    static Singleton* instance;
    
    // 私有构造函数,防止外部实例化
    Singleton() {}
    
public:
    // 获取唯一的对象实例
    static Singleton* GetInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;

B: 在多线程的情况下,可能出现多种使得唯一对象实例创建失败的情况,其中一种情况是在多个线程同时调用 GetInstance() 方法时,可能会导致多个线程同时检测到 instancenullptr,从而同时创建多个对象实例。

C: 为了避免在多线程环境下创建多个对象实例的问题,可以使用线程安全的单例模式实现。一种常见的解决方案是使用加锁机制,通过互斥锁(mutex)来保证只有一个线程能够进入临界区创建对象实例。修改后的代码如下:

#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    
    Singleton() {}
    
public:
    static Singleton* GetInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

在这个修改后的代码中,我们使用了 std::mutex 来创建一个互斥锁对象 mtx,并在 GetInstance() 方法中使用 std::lock_guard 来保证只有一个线程能够进入临界区。这样就能够避免多个线程同时创建多个对象实例的问题。

抽象工厂模式问题:

A: 产品层级是指一组具有共同特征或功能的相关产品的集合。通常这些产品属于同一个类别或领域,但在细节上可能有所不同。

B: 属于多个产品层级的一族对象是指在抽象工厂模式中,有多个产品层级,每个产品层级都有一组相关的产品,而这些产品又有某种关联或配套关系。这些产品层级可以由一个抽象工厂接口来创建。

C: 设计该移动操作系统软件的抽象工厂模式如下:

// 抽象产品:Button
class Button {
public:
    virtual void Render() = 0;
};

// 具体产品:IOSButton
class IOSButton : public Button {
public:
    void Render() {
        // 渲染IOS风格的按钮
    }
};

// 具体产品:WPButton
class WPButton : public Button {
public:
    void Render() {
        // 渲染WP风格的按钮
    }
};

// 抽象产品:Scrollbar
class Scrollbar {
public:
    virtual void Render() = 0;
};

// 具体产品:IOSScrollbar
class IOSScrollbar : public Scrollbar {
public:
    void Render() {
        // 渲染IOS风格的滚动条
    }
};

// 具体产品:WPScrollbar
class WPScrollbar : public Scrollbar {
public:
    void Render() {
        // 渲染WP风格的滚动条
    }
};

// 抽象工厂接口
class AbstractFactory {
public:
    virtual Button* CreateButton() = 0;
    virtual Scrollbar* CreateScrollbar() = 0;
};

// 具体工厂:IOSFactory
class IOSFactory : public AbstractFactory {
public:
    Button* CreateButton() {
        return new IOSButton();
    }
    
    Scrollbar* CreateScrollbar() {
        return new IOSScrollbar();
    }
};

// 具体工厂:WPFactory
class WPFactory : public AbstractFactory {
public:
    Button* CreateButton() {
        return new WPButton();
    }
    
    Scrollbar* CreateScrollbar() {
        return new WPScrollbar();
    }
};

在这个设计中,ButtonScrollbar 是抽象产品,IOSButtonWPButtonIOSScrollbarWPScrollbar 是具体产品。AbstractFactory 是抽象工厂接口,IOSFactoryWPFactory 是具体工厂,分别负责创建对应风格的界面元素。通过使用不同的具体工厂,可以创建出不同风格的界面元素。

单例模式(Singleton)

可以参考下
https://blog.csdn.net/weixin_43956958/article/details/123181421

Singleton 单例模式,不考虑多线程的情况下,java的实现代码如下


//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    //静态工厂方法 
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

如果要考虑多线程,则需要加同步锁,java实现代码如下:

public class Singleton {  
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}  

可以使用加锁机制解决多线程问题。在 GetInstance() 函数中,加入 synchronized 关键字,保证同一时刻只能有一个线程进入创建实例的代码块

答案参考ChatGPT Plus版,整理汇总。希望能帮助你解决问题
A:

class Singleton:
    _instance = None
    
    def __init__(self):
        if Singleton._instance is not None:
            raise Exception("Singleton class cannot be instantiated multiple times.")
        Singleton._instance = self
    
    @staticmethod
    def GetInstance():
        if Singleton._instance is None:
            Singleton()
        return Singleton._instance

B: 在多线程的情况下,可能出现多种使得唯一对象实例创建失败的情况之一是竞态条件。当多个线程同时访问 GetInstance 方法时,可能会同时判断 _instanceNone,然后尝试创建新的实例,导致多个实例被创建。

C: 可以使用线程安全的方式来避免多线程问题。一种常见的解决方案是使用互斥锁(mutex)来保证只有一个线程可以访问创建实例的代码块。下面是修改后的代码:

import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()
    
    def __init__(self):
        if Singleton._instance is not None:
            raise Exception("Singleton class cannot be instantiated multiple times.")
        Singleton._instance = self
    
    @staticmethod
    def GetInstance():
        if Singleton._instance is None:
            with Singleton._lock:
                if Singleton._instance is None:
                    Singleton()
        return Singleton._instance

在修改后的代码中,我们添加了一个互斥锁 _lock,用于保护实例创建的代码块。当一个线程进入互斥锁的作用域时,其他线程将被阻塞,直到该线程释放锁。这样可以确保在多线程环境下只有一个线程能够创建实例。

抽象工厂模式问题:

A: 产品层级是指一组相关的产品类,它们共同实现了某个功能或者提供了一系列相关的操作。

B: 属于多个产品层级的一族对象是指一组相关的产品族,这些产品族包含了多个产品层级的对象,每个产品层级的对象都属于同一个产品族。

C: 使用抽象工厂模式设计该软件,可以定义以下类图:

            +------------------+
            |   GUIFactory    |
            +------------------+
            | + CreateButton() |
            | + CreateScrollbar() |
            +------------------+
                    /\
                    |
        +-------------------+
        |                 |
+----------------+   +----------------+
| IOSFactory     |   | WPFactory     |
+----------------+   +----------------+
| + CreateButton() |   | + CreateButton() |
| + CreateScrollbar()| | + CreateScrollbar()|
+----------------+   +----------------+

在上述类图中,GUIFactory 是抽象工厂,定义了创建按钮和滚动条的接口。IOSFactoryWPFactory 是具体工厂类,分别实现了 GUIFactory 接口,用于创建 IOS 风格和 WP 风格的界面控件。

每个具体工

厂类都实现了 CreateButtonCreateScrollbar 方法,用于创建相应风格的按钮和滚动条对象。这样,通过选择不同的具体工厂类,可以创建对应风格的界面对象。