Factory Pattern
class Creator{ public: virtual std::unique_ptr<Product> create(ProductId id) { if (ProductId::MINE == id) return std::make_unique<ConcreteProductMINE>(); if (ProductId::YOURS == id) return std::make_unique<ConcreteProductYOURS>(); return nullptr; };
|
以上代码是Wiki提供的一段工厂模式的代码,简单来说,工厂模式就是用于一个创建对象的接口,用于创建不同的物品。
object ShapesFactory {
fun <T: Shape> getShape(shape: Class<T>, radius: Int, width: Int, height: Int): Shape { if (shape.isAssignableFrom(Circle::class.java)) { return Circle(radius) } else if (shape.isAssignableFrom(Rectangle::class.java)) { return Rectangle(width, height) } else { throw IllegalStateException("Cannot create shape instance for ${shape.simpleName}") } } }
|
但是,如果想要每个物品有不同的初始参数设置,如果想要传递参数的话,就会比较麻烦,如果放出相同的接口,则会浪费一些参数。同时,每次新添加需要创建的product就会需要大幅度修改接口。
在这篇参考文章中,我看到了作者使用 kotlin 的 sealed class 对数据进行封装。隐藏了接口数据的复杂性。使得代码更加可读,易于拓展,同时限制参数类型。
sealed class ShapeFactoryParam { data class CircleParam(val radius: Int) : ShapeFactoryParam() data class RectangleParam(val width: Int, val height: Int): ShapeFactoryParam() } object ShapesFactory { fun getShape(param: ShapeFactoryParam): Shape { return when (param) { is ShapeFactoryParam.CircleParam -> Circle(param.radius) is ShapeFactoryParam.RectangleParam -> Rectangle(param.width, param.height) } } }
|
Pass Parameter in C++
在c++中,没有像kotlin 里 sealed class 这么好用的东西。
于是在一番寻找后,找到了 variant 这个东西,variant 是一种更通用的union,而且更加type-safe。
同时,有很多方便的标准库函数,也不用自己造轮子了。
在cppreference中,有关于std::visit 添加lambda以及处理不同的类型。
在传递参数时,个人喜欢将param也传递过去,这样子将拆解param全部隐藏到对应的构造函数中。当然,也可以直接就在工厂函数中拆解param。
struct CircleParam{ int radius; }; struct RectangleParam{ int width; int height; };
using ShapeParam = std::variant<CircleParam,RectangleParam>;
class Circle{ public: Circle(const CircleParam& param) : mRadius{param.radius} {} private: int mRadius; };
class ShapeFactoy{ public: static std::unique_ptr<Shape> GetShape(const ShapeParam& params) { return std::visit([](auto&& arg)) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same<T,CircleParam>) { return std::make_unique<Circle>(arg); } else if constexpr(std::is_same<T,RectangleParam>){ return std::make_unique<Rectangle>(arg); } else { static_assert(always_false_v<T>, "non-exhaustive visitor!"); } },params); } };
|
Reference