初学者,自用笔记

用于把“抽象部分(Abstraction)”与“实现部分(Implementation)”解耦, 让它们可以独立变化、自由组合,而不是靠继承层层扩展导致类爆炸

例如,让存储方式在json或xml间快速切换

类似于抽象工厂

  • Abstraction:对外暴露的高层接口/抽象(业务视角),描述规则
  • RefinedAbstraction:抽象的扩展版本(可选)
  • Implementation:实现接口(底层能力视角)
  • ConcreteImplementation:具体实现(A/B/C 多种)

Implementation

// 序列化接口

public interface ISerializer
{
    string Serialize<T>(T data);
    T Deserialize<T>(string text);
}

// 文件读写

public interface IFileIO
{
    void WriteAllText(string fullPath, string text);
    string ReadAllText(string fullPath);
    bool Exists(string fullPath);
    void Delete(string fullPath);
}


ConcreteImplementation

// 序列化具体实现

public sealed class JsonUtilityAdapter : ISerializer
{
    public string Serialize<T>(T data) => JsonUtility.ToJson(data, true);
    public T Deserialize<T>(string text) => JsonUtility.FromJson<T>(text);
}

public sealed class XmlSerializerAdapter : ISerializer
{
    public string Serialize<T>(T data)
    {
        var serializer = new XmlSerializer(typeof(T));
        using (var ms = new MemoryStream())
        {
            serializer.Serialize(ms, data);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public T Deserialize<T>(string text)
    {
        var serializer = new XmlSerializer(typeof(T));
        using (var sr = new StringReader(text))
        {
            return (T)serializer.Deserialize(sr);
        }
    }
}

// 文件读写

public sealed class DiskFileIO : IFileIO
{
    public void WriteAllText(string fullPath, string text)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
        File.WriteAllText(fullPath, text, Encoding.UTF8);
    }

    public string ReadAllText(string fullPath) => File.ReadAllText(fullPath, Encoding.UTF8);
    public bool Exists(string fullPath) => File.Exists(fullPath);
    public void Delete(string fullPath) { if (File.Exists(fullPath)) File.Delete(fullPath); }
}

Abstraction

public sealed class SaveService
{
    private readonly string _dataPath;
    private readonly string _fileName;
    private readonly ISerializer _serializer; // << 桥接:实现端(序列化)可替换
    private readonly IFileIO _fileIO;         // << 桥接:实现端(存储介质)可替换

    private readonly bool _encrypt;
    private readonly string _codeWord = "mycodeword";

    public SaveService(string dataPath, string fileName, ISerializer serializer, IFileIO fileIO, bool encrypt)
    {
        _dataPath = dataPath;
        _fileName = fileName;
        _serializer = serializer;
        _fileIO = fileIO;
        _encrypt = encrypt;
    }

    public void Save(GameData data)
    {
        string fullPath = Path.Combine(_dataPath, _fileName);
        string text = _serializer.Serialize(data);

        if (_encrypt) text = Xor(text);

        _fileIO.WriteAllText(fullPath, text);
    }

    public GameData Load()
    {
        string fullPath = Path.Combine(_dataPath, _fileName);
        if (!_fileIO.Exists(fullPath)) return null;

        string text = _fileIO.ReadAllText(fullPath);
        if (_encrypt) text = Xor(text);

        return _serializer.Deserialize<GameData>(text);
    }

    public void Delete()
    {
        string fullPath = Path.Combine(_dataPath, _fileName);
        _fileIO.Delete(fullPath);
    }

    private string Xor(string s)
    {
        var sb = new StringBuilder(s.Length);
        for (int i = 0; i < s.Length; i++)
            sb.Append((char)(s[i] ^ _codeWord[i % _codeWord.Length]));
        return sb.ToString();
    }
}