Skip to main content

Back To Apple

因為工作關係,加上自己心癢難耐,就買了最新的iPhone 16 PM 和 Macbook Pro 16"了。其實這並不是我第一次用Apple的產品了,我自己一直有一台M1 Mac Mini,電話也有用過iPhone 5s和11 PM。Mac是工作與iOS有關不得不用,說好用嘛Mac Mini只能說還好,至於iPhone則是一直水土不服,信用卡不能跨區/封閉的系統等都使我一直用不了多久就沒用了。

這次一次入手了iPhone和Macbook Pro,加上自己心態也有所不同,這才能理解Apple的生態的確做得非常好。整體的使用上非常順暢自然,而且對我來說資料同步和電量一直是使用電池的電器的痛處,Apple基本上不用煩惱這點。非Apple在資料同步上可使用各種network drive和Localsend,但由於不是原生生態支援,在使用上的確有其不便之處。電量我想就不用說了,x86系列沒一個能做到M系列的能效比與續航,Intel最新的Arrow Lake在參考了Silicon的架構後在續航上進步不少,但代價是失去了x86一直的優點--最高效能輸出,續航也只能在一直保持在低功耗狀態下才能與M2叫板。

說到生態,Apple自己產品的連動幾近於無縫,而Android的話與Windows/KDE/ChromeOS都有連動的途徑,但各有各問題,而ChromeOS這個最大的問題是定位不清,要便宜的只是netbook,要好一點的還真不便宜,而且ChromeOS對我來說最有用的是當成它Linux Container的WM,那其實我根本就不用買一台Chromebook吧。。。

對於遊戲/Windows專用軟件沒需求而工作需長期使用電腦的,Mac的確是理想的選擇。遊戲的話其實還好,現在除了傳統的console外也有不少基於AMD APU的handheld console如Steam deck,除非一些對硬件要求非常高的遊戲如將於下年正式發售的Monster Hunter Wild或RDR2等外,其實足夠應付了。至於Windows專用的軟件。。。節哀順變。

順帶一提,我也有XPS 15的,其實不少Windows的Ultrabook也算很不錯,但很多都會有些奇怪的問題,當中包括Windows自己的問題。XPS 15在日常使用上絕不比Macbook Pro差,除了電量外。。。如果是IT界的用家,想要在XPS上用Linux的話,其實它對Linux的支援也很不錯,但換成其他的Ultrabook的話,firmware就會有各種奇怪的問題了。。。

這個純屬個人感受,沒太多深入體驗,以後有甚麼值得特別寫一篇的我再寫吧,雖然我想大概不會有了,下面貼一下我手上四台Laptop的spec吧

MSI GF63 Thin 11UC (在公司服役中)

component model
CPU Intel 11400H
RAM 2667MHz 16GB x 2
SSD Micron 2210 500Gb
GPU Nvidia 3050

Dell Vostro 3425 (後備急救機)

component model
CPU AMD 5625U
RAM 3200MHz 8GB x 2
SSD Micron 2400 500Gb
GPU iGPU

Dell XPS 15 9520 (遊戲+3D工作,Windows related programming)

component model
CPU Intel 12700H
RAM 4800MHz 32GB x 2
SSD SK hynix PC801 512GB
SSD AITC Kingsman KE680 2TB
GPU Nvidia 3050 Ti

Macbook Pro 16" (App dev,daily use)

component model
CPU M4 Pro 14C
RAM 48GB
SSD 512GB
GPU M4 Pro 20C

Design Pattern - Factory Method Pattern

20250324: 抱歉之前的代碼是錯誤的,現已修正

工廠模式 - Factory Method Pattern

用途: 將建立實體的邏輯放於其規格內部,以達到封裝及資源管理的目的.

例子:

abstract class Logger {
    protected int logLevel;

    Logger(int logLevel) {
        this.logLevel = logLevel;
    }

    // This is the factory method that subclasses must implement
    protected abstract Logger createLogger(int logLevel);

    // The template method that uses the factory method
    static Logger getInstance(int logLevel) {
        LoggerFactory factory = new LoggerFactory();
        return factory.createLogger(logLevel);
    }

    abstract int verbose(String msg);
    abstract int debug(String msg);
    abstract int info(String msg);
    abstract int warn(String msg);
    abstract int error(String msg);
    abstract int fatal(String msg);
    abstract int getLogLevel();
    abstract void setLogLevel(int logLevel);
}

// Factory class that decides which logger to create
class LoggerFactory {
    protected Logger createLogger(int logLevel) {
        if (env == "DEBUG") {
            return new DebugLogger(logLevel);
        }
        return new ReleaseLogger(logLevel);
    }
}

// Or even better, separate factories for each type
class DebugLoggerFactory extends LoggerFactory {
    @Override
    protected Logger createLogger(int logLevel) {
        return new DebugLogger(logLevel);
    }
}

class ReleaseLoggerFactory extends LoggerFactory {
    @Override
    protected Logger createLogger(int logLevel) {
        return new ReleaseLogger(logLevel);
    }
}
const DEFAULT_LOG_LEVEL = 3;
const AVAILABLE_LOG_LEVEL = [
    'trace',
    'debug',
    'log',
    'info',
    'warn',
    'error'
];

// Abstract factory (using closure)
const createLoggerFactory = () => {
    // This is the abstract factory method that concrete factories must implement
    const createLogger = (logLevel) => {
        throw new Error('Concrete factories must implement createLogger');
    };

    return {
        createLogger
    };
};

// Concrete factory for debug logging
const createDebugLoggerFactory = () => {
    const loggerInstance = AVAILABLE_LOG_LEVEL.reduce((acc, level) => {
        return {...acc, [level]: (msg) => console[level](msg)};
    }, {});

    const createLogger = (logLevel) => {
        let currentLogLevel = logLevel ?? DEFAULT_LOG_LEVEL;
        return {
            ...loggerInstance,
            setLogLevel: (_logLevel) => {currentLogLevel = _logLevel},
            getLogLevel: () => currentLogLevel,
        };
    };

    return {
        createLogger
    };
};

// Concrete factory for release logging
const createReleaseLoggerFactory = () => {
    const createLogger = (logLevel) => {
        let currentLogLevel = logLevel ?? DEFAULT_LOG_LEVEL;

        const logFnMeta = (level) => {
            if (currentLogLevel <= level)
                return (msg) => console[level](msg);
            else
                return (_) => {};
        };

        const loggerInstance = AVAILABLE_LOG_LEVEL.reduce((acc, level) => {
            return {...acc, [level]: logFnMeta(level)};
        }, {});

        return {
            ...loggerInstance,
            setLogLevel: (_logLevel) => {
                currentLogLevel = _logLevel;
                // Recreate logger instance with new log level
                Object.assign(loggerInstance, AVAILABLE_LOG_LEVEL.reduce((acc, level) => {
                    return {...acc, [level]: logFnMeta(level)};
                }, {}));
            },
            getLogLevel: () => currentLogLevel,
        };
    };

    return {
        createLogger
    };
};

// Factory selector
const logger = (logLevel) => {
    const factory = env === 'DEBUG' 
        ? createDebugLoggerFactory() 
        : createReleaseLoggerFactory();

    return factory.createLogger(logLevel);
};

export default logger;

以上兩個code snippet以logger為例,說明了取得logger的資源調用方不用處理logLevel的變動所造成的影響,也不用知道現在的環境是debug還是release,這些變量都由instance提供方處理,以符合single responsibility principle單一責任原則.

2024四月東京旅行(日光,秩父,大洗)

2024四月日本旅行遊記

因為超多圖,所以default hide,click圖可以開大圖
第一日

係品川Prince Sakura Hotel住
睇圖








夜晚食焼肉ジャンボはなれ
睇圖











第二日

朝早淺草
睇圖





去日光
睇圖

日光東照宮
睇圖

































經過いろは坂上左山
睇圖




















第三日

Katsuプリポー
睇圖







焼鳥おみ乃
睇圖



































第四日

恵比寿えんどう
睇圖



























Pâtisserie Ryoco
睇圖




うなぎ魚政
睇圖










第五日

秩父ーーあの花聖地巡礼と芝桜
睇圖























































蕃YORONIKU
睇圖
























第六日

水戸 轉車短暫停留
睇圖





大洗
睇圖


















































































































味処 大森
睇圖
















又開番個blog

Well...本身係想等到我個markdown parser + static page generator先開,但應該過多十年都唔會寫完,就用住現成嘅framework先,thanks a lot with Nikola,雖然setup有d麻煩,但做完demo感覺唔錯,用住先is ok

之後個focus應該會去左gaming related(Godot + F#, 用慣FP),始終拖左太耐啦...