OO Design — where to put non-member functions
我有一个带有许多参数的复杂构造过程的类。多个客户机共享该类的对象,这些客户机参数的联合用于实例化该类。因此,我有一个工厂类,它存储这些需求,检查各种客户机请求的一致性,并实例化该类。
此外,还有一组通用的使用模型(或参数集),多个客户机用于多个工厂。
例如,考虑一个例子。(注意,实际代码是C++,但我的经验是Python,所以我将在Python中使用伪代码。是的,我知道这个例子实际上不会像现在这样工作。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Classroom: def __init__(self, room_size=None, n_desks=None, n_boards=None, n_books=None, has_globe=False, ... ): ... class ClassroomFactory: def __init__(self): self._requirements = dict() def addRequirement(self, name, value): if name.startswith("n_"): self._requirements[name] = max(value, self._requirements.get(name, 0)) ... def createClassroom(self): return Classroom(**self._requirements) # instantiate the factory factory = ClassroomFactory() #"client 1" is a geography teaacher factory.addRequirement("n_desks", 10) factory.addRequirement("n_boards", 1) factory.addRequirement("has_globe", True) #"client 2" is a math teacher factory.addRequirement("n_desks", 10) factory.addRequirement("n_boards", 1) #"client 3" is a after-school day-care factory.addRequirement("room_size", (20,20)) factory.addRequirement("has_carpet", True) room = factory.createClassroom() |
常用的模式是当老师,我们需要10张课桌和一块黑板。我认为这最好由非成员函数/修饰器提供,比如:
1 2 3 4 | def makeTeacherRoom(factory): factory.addRequirement("n_desks", 10) factory.addRequirement("n_boards", 1) return factory |
这似乎是"更喜欢非会员/非朋友对会员"模式的一个很好的例子。
我正在努力解决的问题是,在一个更大的OO代码框架内,这些类型的非成员函数/修饰符应该在哪里,无论是在名称空间还是实际文件方面?
它们应该存在于工厂的文件/命名空间中吗?它们与工厂有着密切的联系,但它们对一般工厂是有限制的,不需要使用工厂。
它们应该存在于客户端的文件/命名空间中吗?客户机理解这些使用模型,但这将限制多个客户机之间的重用。
如果它们与客户机的公共基类(例如,可以想象一个"teacher"类/命名空间,它还提供了非成员函数makeTeacherRoom(),该函数将由MathTeacher和GeographyTeacher继承。
他们应该完全生活在其他地方吗,在"utils"文件中?如果是,在哪个名称空间?
这主要是个人决定。你的大多数选择都没有技术上的负面影响。例如:
我通常会创建一个相关命名的util文件(或使用静态方法的类),并将其放在与其使用的类(更有用的mulate版本)相同的命名空间中。对于
我见过一个命名变体,
我个人会让他们成为班上的静态成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class File { public: static bool load( File & file, std::string const & fileName ); private: std::vector< char > data; }; int main( void ) { std::string fileName ="foo.txt"; File myFile; File::load( myFile, fileName ); } |
使用静态方法,它们可以访问类的私有数据,而不属于类的特定实例。它还意味着方法不会与它们所作用的数据分离,如果您将它们放在某个实用程序头中,情况也会如此。
您可能需要为应用程序处理单例类中的非成员函数。工厂可以从程序或其他对象执行。
C++支持全局函数(非成员函数),但是,为应用程序使用单个对象,"做这个把戏"。
此外,由于"classroom"对象可以用许多可选参数进行实例化,因此在调用构造函数(python中的"in it")之后,您可能需要分配它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | // filename:"classrooms.cpp" class ClassroomClass { protected: int _Room_Size; int _N_Desks; int _N_Boards; int _N_Books; bool _Has_Globe; public: // constructor without parameters, // but, can be declared with them ClassroomClass() { _Room_Size = 0; _N_Desks = 0; _N_Boards = 0; _N_Books = 0; _Has_Globe = false; } // ClassroomClass() public int get_Room_Size() { return _Room_Size; } public void set_Room_Size(int Value) { _Room_Size = Value; } // other"getters" &"setters" functions // ... } // class ClassroomClass class ClassroomFactoryClass { public: void addRequirement(char[] AKey, char[] AValue); } // class ClassroomFactoryClass class MyProgramClass { public: ClassroomFactoryClass Factory; public: void makeTeacherRoom(); void doSomething(); } // class MyProgramClass void MyProgramClass::addRequirement(char[] AKey, char[] AValue) { ... } // void MyProgramClass::addRequirement(...) void MyProgramClass::makeTeacherRoom() { Factory.addRequirement("n_desks","10") Factory.addRequirement("n_boards","1") } // void MyProgramClass::makeTeacherRoom(...) void MyProgramClass::doSomething() { ... } // void MyProgramClass::doSomething(...) int main(char[][] args) { MyProgramClass MyProgram = new MyProgramClass(); MyProgram->doSomething(); delete MyProgram(); return 0; } // main(...) |
干杯