Created
June 6, 2018 20:52
-
-
Save DBJDBJ/c4df39f5df2188de41dce6de260a7c58 to your computer and use it in GitHub Desktop.
Swappable Engine Factory, I think a better variation to the Factory Pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
/* | |
Swappable Engine Factory, I think a better variation to the | |
Factory Pattern | |
Usage: | |
using namespace car_factory; | |
auto car_1 = | |
assembly_line( | |
engine_tag::old ); | |
car_1.start(); | |
*/ | |
#include <utility> | |
namespace car_factory { | |
// interface to swapable engines | |
enum class engine_tag : char { old = 'O', next = 'N' }; | |
namespace engine_workshop { // hidden from clients | |
// interface to swapable engines | |
struct IEngine { virtual engine_tag start() = 0; }; | |
// switchable engines | |
struct old : public IEngine { virtual engine_tag start() override { return engine_tag::old; } }; | |
struct next : public IEngine { virtual engine_tag start() override { return engine_tag::next; } }; | |
} // inner | |
// facade of the solution | |
// this is not ABC | |
class Automobile final { | |
using IEngine = typename engine_workshop::IEngine ; | |
// we use the simple native pointer | |
// thus swap idiom is very easy to implement | |
mutable IEngine * engine_{}; | |
// this ctor is visible to the factory method | |
// we do not want this as a "converting constructor" | |
// ditto we declare it as explicit | |
explicit Automobile( IEngine * use_) : engine_(use_) {} | |
// no default ctor | |
// no nullptr engine | |
Automobile() = delete; | |
// the factory function declaration | |
friend Automobile assembly_line(engine_tag); | |
public: | |
// delegating to the engine | |
// inheritance is evil | |
engine_tag start() const { return engine_->start(); } | |
// it is easy to manage the pointer lifetime | |
~Automobile() { delete engine_; } | |
/* | |
required move semantics | |
NOTE: we can not allow for move or copy assignment | |
since this will effectively and quietly | |
change the engine "mid flight" | |
*/ | |
// no copy | |
Automobile(const Automobile&) = delete; | |
Automobile& operator=(const Automobile&) = delete; | |
// move | |
Automobile(Automobile&& other_) noexcept { std::swap(this->engine_, other_.engine_); } | |
Automobile& operator=(Automobile&& other_) = delete; // noexcept { std::swap(this->engine_, other_.engine_); return *this; } | |
}; | |
// factory inserts the engine on production line | |
// we do not return ABC so we enjoy the value semantics | |
inline Automobile assembly_line (engine_tag which_) | |
{ | |
// I assume I do not need std::move in here | |
// I could also use std::enable_if and std::is_move_constructible | |
// in return value type to check the Automobile type movability | |
// or I could just leave it to the CL | |
using namespace engine_workshop; | |
if (engine_tag::next == which_ ) | |
return Automobile(new next{}); | |
if (engine_tag::old == which_) | |
return Automobile(new old{}); | |
throw std::runtime_error{ __FUNCSIG__ " Unknown engine_tag ordered?"}; | |
} | |
} | |
/* | |
Copyright 2018 by [email protected] | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http ://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment