Less APIs or more encapsulation? - oop

3 class, A contains B, B contains C. So user want to use some service of C, there are two choice:
First, more encapsulation:
class A:
def newMethod(self):
self.b.newMethod()
class B:
def newMethod(self):
self.c.newMethod()
class C:
def newMethod(self):
#do something
pass
a.newMethod()
Call service of c directly:
class A:
pass
class B:
pass
class C:
def newMethod(self):
#do something
pass
b = a.b
c = a.c
c.newMethod()
Generally, what I learned from books told me that 1st choice is better.
But when C has many many methods to expose to outer user, 2nd choice seems to be more reasonable. And in the first design, A and B did nothing really useful.
What will you choose?

Get your objects to do things for you, rather than asking them for their data and doing stuff with it.
If c in your example is exposing a lot of methods, I would suggest that you shouldn't be exposing these to a and your clients, but rather a and b should be working together to use these methods on behalf of the client.
A good indicator of a problem is a class that contains data, and provides getters for those data items, and the client code accessing that data and then performing work (DAOs excepted). In this (common) scenario the class most likely shouldn't be exposing that data (and perhaps breaking encapsulation), but rather doing the work for that client (either by having that functionality, or perhaps some injectable strategy object).
Check out the Law of Demeter (the linked document looks rather dry and academic, regrettably), which offers some good guidelines as to how objects and members should communicate.

Related

Which objects own the method? Translating from discrete math

So, suppose I'm working in the world of discrete mathematics and I have some function
f: A x B x C -> D.
With this function I can make computations like f(a,b,c) = d. (I'm being vague here on purpose).
Now suppose I want to implement this computation explicitly in some modern OO programming language. So I initialize a variable called a of class ClassA and so on with b and c. Then what? Which object should own the computation? Or could it be an initializer. Could it be a static function?
I could have:
d = a.f_1(b,c),
d = b.f_2(a,c),
d = c.f_3(a,b),
d = new ObjD(a,b,c),
d = ZStatic.f_4(a,b,c)
all as plausible options, couldn't I?
Given the situation, should symmetry demand I implement all of these options?
I'd prefer to avoid the constructor approach completely, but beyond that I don't know what progress could be made other than the assumption of essentially arbitrary information.
So, what object should own the function $f$, if any?
To give the best answer, it is important to know what kind of variables you use.
A very important metric in oop is to achieve high cohesion. Cohesion is the degree to which the elements of a module belong together. If your variables a,b and c belong together in a specific context, then it should be the best solution to put them in exactly one class. And if they are in one class you should not worry about, which class should own the computation (your fourth solution).
Your last suggestion, to use a static function is also conceivable. This approach is often used in mathematic librarys in different kind of languages (e.g. Java: Math class)

OOP: class inheritance to add just one property vs constructor argument

I'm new to OOP and I'm in the following situation: I have something like a report "Engine" that is used for several reports, the only thing needed is the path of a config file.
I'll code in Python, but this is an agnostic question.So, I have the following two approaches
A) class ReportEngine is an abstract class that has everything needed BUT the path for the config file. This way you just have to instantiate the ReportX class
class ReportEngine(object):
...
class Report1(ReportEngine):
_config_path = '...'
class Report2(ReportEngine):
_config_path = '...'
report_1 = Report1()
B) class ReportEngine can be instantiated passing the config file path
class ReportEngine(object):
def __init__(self, config_path):
self._config_path = config_path
...
report_1 = ReportEngine(config_path="/files/...")
Which approach is the right one? In case it matters, the report object would be inserted in another class, using composition.
IMHO the A) approach is better if you need to implement report engines that are different from each other. If your reports are populated using different logic, follow this approach.
But if the only difference among your report engines is the _config_path i think that B) approach is the right one for you. Obviosly, this way you'll have a shared logic to build every report, regardless the report type.
Generally spoken, put everything which every Report has, in the superclass. Put specific things in the subclasses.
So in your case, put the _config_path in the superclass ReportEngine like in B) (since every Report has a _config_path), but instanciate specific Reports like in A), whereas every Report can set its own path.
I don't know Python, but did a quick search for the proper syntax for Python 3.0+, I hope it makes sense:
class ReportEngine(object):
def __init__(self, config_path):
self._config_path = config_path
def printPath(self):
print self._config_path
...
class Report1(ReportEngine):
def __init__(self):
super().__init__('/files/report1/...')
Then a
reportObj = Report1()
reportObj.printPath()
should print
'/files/report1/...'
Basically the main difference is that approach A is more flexible than B(not mutual change in one report does not influence other reports), while B is simpler and clearer (shows exactly where the difference is) but a change affecting one report type would require more work. If you are pretty sure the reports won't change in time - go with B, if you feel like the differences will not be common in the future - go with A.

Designing operation (a,b) -> (c,d)

I have an operation that I need to design. That operation takes two objects of a certain class X, and returns two new objects of the same class (I may need the originals later). The logic that dictates the selection of this object is contained in class Y. On one hand, I don't want class Y to know details about class X implementation; on the other, I don't want class X to know details about selecting the different objects to perform this operation on.
If that was all the problem, I'd just create a static method on class A. However, the methods in language I'm working on return only one object. Also, the operation needs to be robust, and calling operation two times to get C and D respectively isn't possible, as both C & D both rely on a single random number.
How should I design such operation?
Update: I'm using Obejctive C.
I decided to just modify given objects A & B with a static method. I'll have to make copies of them before calling this method, but I think it'll be not slower than creating new ones; most of the information in objects C & D is derived from A & B anyway.
(I still think it's an ugly solution, and will welcome a more qualified answer).

OO design: Copying data from class A to B

Having the SOLID principles and testability in mind, consider the following case:
You have class A and class B which have some overlapping properties. You want a method that copies and/or converts the common properties from class A to class B. Where does that method go?
Class A as a B GetAsB() ?
Class B as a constructor B(A input)?
Class B as a method void FillWithDataFrom(A input)?
Class C as a static method B ConvertAtoB(A source)?
???
It depends, all make sense in different circumstances; some examples from Java:
String java.lang.StringBuilder.toString()
java.lang.StringBuilder(String source)
void java.util.GregorianCalender.setTime(Date time)
ArrayList<T> java.util.Collections.list(Enumeration<T> e)
Some questions to help you decide:
Which dependency makes more sense? A dependent on B, B dependent on A, neither?
Do you always create a new B from an A, or do you need to fill existing Bs using As?
Are there other classes with similar collaborations, either as data providers for Bs or as targets for As data?
I'd rule out 1. because getter methods should be avoided (tell, don't ask principle).
I'd rule out 2. because it looks like a conversion, and this is not a conversion if A and B are different classes which happens to have something in common. At least, this is what it seems from the description. If that's not the case, 2 would be an option too IMHO.
Does 4. implies that C is aware of inner details of B and/or C? If so, I'd rule out this option too.
I'd vote for 3. then.
Whether this is correct OOP theory or not is up for debate, but depending upon the circumstances, I wouldn't rule C out quite so quickly. While ti DOES create a rather large dependency, it can have it's uses if the specific role of C is to manage the interaction (and copying) from A to B. The dependency is created in C specifically to avoid creating such dependency beteween A and B. Further, C exists specifically to manage the dependency, and can be implemented with that in mind.
Ex. (in vb.Net/Pseudocode):
Public Class C
Public Shared Function BClassFactory(ByVal MyA As A) As B
Dim NewB As New B
With B
.CommonProperty1 = A.CommonProperty1
.CommonProperty2 = A.CommonProperty2
End With
Return B
End Function
End Class
If there is a concrete reason to create, say, a AtoBConverterClass, this approach might be valid.
Again, this might be a specialized case. However I have found it useful on occasion. Especially if there are REALLY IMPORTANT reasons to keep A and B ignorant of eachother.

Data Mapper: Is my interpretation correct?

I'm trying to confirm now, what I believe about the Data Mapper pattern. So here we go:
Section A:
A Data Mapper is a class which is used to create, update and delete objects of another Class. Example: A class called Cat, and a Data Mapper called CatDataMapper. And a database table called cats. But it could also be an xml file called cats.xml, or an hard-coded array called cats. The whole point of that Data Mapper is to free the Business Logic which uses the Cat class from thinking about "how to get an exisiting cat", or "how to save a cat", "where to save a cat". As a user of the Data Mapper it looks like a blackbox with well-defined methods like getCat(int id), saveCat(Cat catObject), deleteCat(Cat catObject), and so on.
Section B:
First I thought it would be clever if Cat inherits from CatDataMapper, because calling such functions then is a bit more convenient. For example, methods like catWithId(int id) could be static (class method) and return an instance of a Cat, initialized with data from anywhere. And when I work with a cat object in my code, I could simply call myCat->save(); to store it whereever the Data Mapper will store it (don't care where and how, the Data Mapper hides this complexity from the user).
In conclusion, I'm a little bit confused now ;)
Do you think that Section A is valid for the Data Mapper pattern? And if I would do it additionaly as described in Section B, would that be bad? Why?
I think your Section A corresponds to the definiton of the Data Mapper pattern as given by Martin Fowler
Be careful with the details of your implementation language. In Section B having catWithId() be a static member of the cat class may interfere with polymorphic behavior of the method.
In java, the JVM will dispatch a static method based on the declared type of the reference.
Try this out:
1. create a class CatDataMapper with the static method catWithId(int id)
2. create a class Cat extending CatDataMapper that has the desired Business Logic behavior
3. subclass Cat with LoggedCat that logs all activity, including the activity from CatDataMapper
4. do Cat foo = new LoggedCat()
5. do Cat bar = foo.catWithId(5)
note which method is called, it should be the static method of CatDataMapper not the static method of LoggedCat
http://faq.javaranch.com/view?OverridingVsHiding gives a more in-depth discussion of this.
I think this is an OK approach. Aside from the naming conventions used, you're following a well known Data Access pattern here and you're allowing the users of the Cat objects to perform CRUD operations without having to talk to the CatDataMapper which is always a plus in my book.
I would usggest looking at Spring Container technology for this if you're in the java world.