├── LICENSE ├── README.md ├── after.py └── before.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ArjanCodes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 7 The Factory Pattern in Python 2 | 3 | This repository contains the code for the The Factory Pattern in Python video on the ArjanCodes channel. Watch the video [here](https://youtu.be/s_4ZrtQs8Do). 4 | 5 | The example is about video and audio exporting. In `before.py`, you find the original code. The `after.py` file contains a version where the factory pattern is used. 6 | -------------------------------------------------------------------------------- /after.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic video exporting example 3 | """ 4 | 5 | import pathlib 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class VideoExporter(ABC): 10 | """Basic representation of video exporting codec.""" 11 | 12 | @abstractmethod 13 | def prepare_export(self, video_data): 14 | """Prepares video data for exporting.""" 15 | 16 | @abstractmethod 17 | def do_export(self, folder: pathlib.Path): 18 | """Exports the video data to a folder.""" 19 | 20 | 21 | class LosslessVideoExporter(VideoExporter): 22 | """Lossless video exporting codec.""" 23 | 24 | def prepare_export(self, video_data): 25 | print("Preparing video data for lossless export.") 26 | 27 | def do_export(self, folder: pathlib.Path): 28 | print(f"Exporting video data in lossless format to {folder}.") 29 | 30 | 31 | class H264BPVideoExporter(VideoExporter): 32 | """H.264 video exporting codec with Baseline profile.""" 33 | 34 | def prepare_export(self, video_data): 35 | print("Preparing video data for H.264 (Baseline) export.") 36 | 37 | def do_export(self, folder: pathlib.Path): 38 | print(f"Exporting video data in H.264 (Baseline) format to {folder}.") 39 | 40 | 41 | class H264Hi422PVideoExporter(VideoExporter): 42 | """H.264 video exporting codec with Hi422P profile (10-bit, 4:2:2 chroma sampling).""" 43 | 44 | def prepare_export(self, video_data): 45 | print("Preparing video data for H.264 (Hi422P) export.") 46 | 47 | def do_export(self, folder: pathlib.Path): 48 | print(f"Exporting video data in H.264 (Hi422P) format to {folder}.") 49 | 50 | 51 | class AudioExporter(ABC): 52 | """Basic representation of audio exporting codec.""" 53 | 54 | @abstractmethod 55 | def prepare_export(self, audio_data): 56 | """Prepares audio data for exporting.""" 57 | 58 | @abstractmethod 59 | def do_export(self, folder: pathlib.Path): 60 | """Exports the audio data to a folder.""" 61 | 62 | 63 | class AACAudioExporter(AudioExporter): 64 | """AAC audio exporting codec.""" 65 | 66 | def prepare_export(self, audio_data): 67 | print("Preparing audio data for AAC export.") 68 | 69 | def do_export(self, folder: pathlib.Path): 70 | print(f"Exporting audio data in AAC format to {folder}.") 71 | 72 | 73 | class WAVAudioExporter(AudioExporter): 74 | """WAV (lossless) audio exporting codec.""" 75 | 76 | def prepare_export(self, audio_data): 77 | print("Preparing audio data for WAV export.") 78 | 79 | def do_export(self, folder: pathlib.Path): 80 | print(f"Exporting audio data in WAV format to {folder}.") 81 | 82 | 83 | class ExporterFactory(ABC): 84 | """ 85 | Factory that represents a combination of video and audio codecs. 86 | The factory doesn't maintain any of the instances it creates. 87 | """ 88 | 89 | @abstractmethod 90 | def get_video_exporter(self) -> VideoExporter: 91 | """Returns a new video exporter belonging to this factory.""" 92 | 93 | @abstractmethod 94 | def get_audio_exporter(self) -> AudioExporter: 95 | """Returns a new audio exporter belonging to this factory.""" 96 | 97 | 98 | class FastExporter(ExporterFactory): 99 | """Factory aimed at providing a high speed, lower quality export.""" 100 | 101 | def get_video_exporter(self) -> VideoExporter: 102 | return H264BPVideoExporter() 103 | 104 | def get_audio_exporter(self) -> AudioExporter: 105 | return AACAudioExporter() 106 | 107 | 108 | class HighQualityExporter(ExporterFactory): 109 | """Factory aimed at providing a slower speed, high quality export.""" 110 | 111 | def get_video_exporter(self) -> VideoExporter: 112 | return H264Hi422PVideoExporter() 113 | 114 | def get_audio_exporter(self) -> AudioExporter: 115 | return AACAudioExporter() 116 | 117 | 118 | class MasterQualityExporter(ExporterFactory): 119 | """Factory aimed at providing a low speed, master quality export.""" 120 | 121 | def get_video_exporter(self) -> VideoExporter: 122 | return LosslessVideoExporter() 123 | 124 | def get_audio_exporter(self) -> AudioExporter: 125 | return WAVAudioExporter() 126 | 127 | 128 | def read_factory() -> ExporterFactory: 129 | """Constructs an exporter factory based on the user's preference.""" 130 | 131 | factories = { 132 | "low": FastExporter(), 133 | "high": HighQualityExporter(), 134 | "master": MasterQualityExporter(), 135 | } 136 | while True: 137 | export_quality = input("Enter desired output quality (low, high, master): ") 138 | if export_quality in factories: 139 | return factories[export_quality] 140 | print(f"Unknown output quality option: {export_quality}.") 141 | 142 | 143 | def main(fac: ExporterFactory) -> None: 144 | """Main function.""" 145 | 146 | # retrieve the exporters 147 | video_exporter = fac.get_video_exporter() 148 | audio_exporter = fac.get_audio_exporter() 149 | 150 | # prepare the export 151 | video_exporter.prepare_export("placeholder_for_video_data") 152 | audio_exporter.prepare_export("placeholder_for_audio_data") 153 | 154 | # do the export 155 | folder = pathlib.Path("/usr/tmp/video") 156 | video_exporter.do_export(folder) 157 | audio_exporter.do_export(folder) 158 | 159 | 160 | if __name__ == "__main__": 161 | # create the factory 162 | factory = read_factory() 163 | 164 | # perform the exporting job 165 | main(factory) 166 | -------------------------------------------------------------------------------- /before.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic video exporting example 3 | """ 4 | 5 | import pathlib 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class VideoExporter(ABC): 10 | """Basic representation of video exporting codec.""" 11 | 12 | @abstractmethod 13 | def prepare_export(self, video_data): 14 | """Prepares video data for exporting.""" 15 | 16 | @abstractmethod 17 | def do_export(self, folder: pathlib.Path): 18 | """Exports the video data to a folder.""" 19 | 20 | 21 | class LosslessVideoExporter(VideoExporter): 22 | """Lossless video exporting codec.""" 23 | 24 | def prepare_export(self, video_data): 25 | print("Preparing video data for lossless export.") 26 | 27 | def do_export(self, folder: pathlib.Path): 28 | print(f"Exporting video data in lossless format to {folder}.") 29 | 30 | 31 | class H264BPVideoExporter(VideoExporter): 32 | """H.264 video exporting codec with Baseline profile.""" 33 | 34 | def prepare_export(self, video_data): 35 | print("Preparing video data for H.264 (Baseline) export.") 36 | 37 | def do_export(self, folder: pathlib.Path): 38 | print(f"Exporting video data in H.264 (Baseline) format to {folder}.") 39 | 40 | 41 | class H264Hi422PVideoExporter(VideoExporter): 42 | """H.264 video exporting codec with Hi422P profile (10-bit, 4:2:2 chroma sampling).""" 43 | 44 | def prepare_export(self, video_data): 45 | print("Preparing video data for H.264 (Hi422P) export.") 46 | 47 | def do_export(self, folder: pathlib.Path): 48 | print(f"Exporting video data in H.264 (Hi422P) format to {folder}.") 49 | 50 | 51 | class AudioExporter(ABC): 52 | """Basic representation of audio exporting codec.""" 53 | 54 | @abstractmethod 55 | def prepare_export(self, audio_data): 56 | """Prepares audio data for exporting.""" 57 | 58 | @abstractmethod 59 | def do_export(self, folder: pathlib.Path): 60 | """Exports the audio data to a folder.""" 61 | 62 | 63 | class AACAudioExporter(AudioExporter): 64 | """AAC audio exporting codec.""" 65 | 66 | def prepare_export(self, audio_data): 67 | print("Preparing audio data for AAC export.") 68 | 69 | def do_export(self, folder: pathlib.Path): 70 | print(f"Exporting audio data in AAC format to {folder}.") 71 | 72 | 73 | class WAVAudioExporter(AudioExporter): 74 | """WAV (lossless) audio exporting codec.""" 75 | 76 | def prepare_export(self, audio_data): 77 | print("Preparing audio data for WAV export.") 78 | 79 | def do_export(self, folder: pathlib.Path): 80 | print(f"Exporting audio data in WAV format to {folder}.") 81 | 82 | 83 | def main() -> None: 84 | """Main function.""" 85 | 86 | # read the desired export quality 87 | export_quality: str 88 | while True: 89 | export_quality = input("Enter desired output quality (low, high, master): ") 90 | if export_quality in {"low", "high", "master"}: 91 | break 92 | print(f"Unknown output quality option: {export_quality}.") 93 | 94 | # create the video and audio exporters 95 | video_exporter: VideoExporter 96 | audio_exporter: AudioExporter 97 | if export_quality == "low": 98 | video_exporter = H264BPVideoExporter() 99 | audio_exporter = AACAudioExporter() 100 | elif export_quality == "high": 101 | video_exporter = H264Hi422PVideoExporter() 102 | audio_exporter = AACAudioExporter() 103 | else: 104 | # default: master quality 105 | video_exporter = LosslessVideoExporter() 106 | audio_exporter = WAVAudioExporter() 107 | 108 | # prepare the export 109 | video_exporter.prepare_export("placeholder_for_video_data") 110 | audio_exporter.prepare_export("placeholder_for_audio_data") 111 | 112 | # do the export 113 | folder = pathlib.Path("/usr/tmp/video") 114 | video_exporter.do_export(folder) 115 | audio_exporter.do_export(folder) 116 | 117 | 118 | if __name__ == "__main__": 119 | main() 120 | --------------------------------------------------------------------------------