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四月東京旅行(日光,秩父,大洗)
又開番個blog
Well...本身係想等到我個markdown parser + static page generator先開,但應該過多十年都唔會寫完,就用住現成嘅framework先,thanks a lot with Nikola,雖然setup有d麻煩,但做完demo感覺唔錯,用住先is ok
之後個focus應該會去左gaming related(Godot + F#, 用慣FP),始終拖左太耐啦...
by Phil Lui