这是一般软件设计问题。
使用#if编译器指令来支持多个平台是一个好主意。例如,我有三个文件:
IScreen.cs
public interface IScreen {
...
}
ScreenWin.cs
#if WIN
public class Screen : IScreen {
...
}
#endif
ScreenMac.cs
#if WIN
public class Screen : IScreen {
...
}
#endif
这似乎很酷,我可以使用BDD,并且有类似的东西:
Given a Screen exists with width: 1920 and height: 1080
将根据编译器指令使用正确的屏幕。
这似乎比尝试使用抽象工厂的性能更好。
有什么缺点?
答案 0 :(得分:2)
正如@Oded所回答的那样,使用编译时directoves的下行代码是你必须为每个平台编译一个特定的二进制文件。好的一面是,你没有一个臃肿的“一刀切”应用程序,因为它与平台无关,所以在每个平台上都会变得越来越慢。
#if的另一个缺点是很多Visual Studio工具只考虑“当前活动”的代码。例如,智能感知和重构工具 - 如果您希望将IScreen重命名为IDisplay,那么您会发现重构工作正常并且您的所有PC代码都已完美更新,但您的所有Mac代码都将被严重破坏,因为重构工具根本不会“请参阅“其他代码分支。同样,很容易对PC分支上的代码进行更改,忘记对Mac分支进行相应的更改,再次破坏它。
工厂而不是“#if”的好处是可以在每个平台上运行单个二进制映像,并且在创建具体实现时只需要检查一次主机平台(因此它仍然非常有效)运行时,但会更大,因为你必须在一个发行版中发布所有平台变体)
然而,通过使用更模块化的设计模式而不是#if:使用附属程序集来实现特定于平台的实现,可以充分利用这两个领域。在这种方法中,主应用程序代码将指定IScreen
接口,然后您将具有Concrete Screen
(Mac)和Screen
(PC)类单独的平台特定的ScreenImplementation.dll程序集变体。您还可以发布涵盖所有平台的单个安装程序(通过简单地为主机平台部署适当的卫星dll)。这为您提供了使用#if的边际效率/大小改进,但实际上不得不用条件搞乱您的代码。 (当然,这种模块化方法对#if和Factory设计都有意义 - 一旦将特定于平台的实现拆分为单独的程序集,它们就变成了部署选项,而不是核心实现架构)
答案 1 :(得分:1)
缺点包括必须编译多个二进制文件 - 每个平台一个。
如果不小心,您可能会在代码的许多部分使用预处理程序指令使代码混乱。请参阅this关于撤消一个此类代码库的问题。
如果您可以在代码中检测平台,那么这是一种更好的方法。