The UML 2.5.1 specification states about association-end ownership:
Dot notation is used to denote association end ownership, where the dot shows that the Class at the other end of the line owns the Property whose type is the Class touched by the dot.
And it states about association-end navigability:
Arrow notation is used to denote association end navigability. By definition, all class-owned association ends are navigable.
I can clearly see why an association end that is class-owned is navigable:
class A:
def __init__(self, b):
self.b = b # class-owned
class B:
pass
b = B()
a = A(b)
a.b # navigable
However I have more trouble figuring out how an association-end that is association-owned (so not class-owned) could be navigable?
The specification states that associations can be represented with association classes:
An AssociationClass can be seen as an Association that also has Class properties, or as a Class that also has Association properties.
So I tried to implement the association with a Python class (like in SQL where associations are often implemented with SQL association tables when the association ends are association-owned), but without much success:
class A:
pass
class B:
pass
class A_B: # association class
def __init__(self, a, b):
self.a = a # association-owned
self.b = b # association-owned
b = B()
a = A()
a_b = A_B(a, b)
a.b # not navigable (AttributeError)
In your own answer you claim that A_B is an association class. This is indeed a valid interpretation.
But it's not the only one:
An Association declares that there can be links between instances whose types conform to or implement the associated types. A link is a tuple with one value for each memberEnd of the Association, where each value is an instance whose type conforms to or implements the type at the end. (section 11.5.3.1)
Your python class A_B fully meets this definition: it implements such a link between the associated types. In fact, it provides nothing more an nothing less than the functionality of a tuple (in the abstract sense).
The classes of your model are not necessarily related one to one to your implementation classes. Modelling means to take a viewpoint on the world. The story of the elephant and the blind persons tells us, there are often several valid view points. So, up to you to chose the one which helps you best to solve your problem.
Additional remark: Classes like A_B are frequently used to implement many-to-many associations. A similar choice exists when ternary associations are involved: some prefer to see them as a binary association class having an association with a third class. Some prefer to see it as a simple N-ary association. Both would probably be implemented with using an class A_B_C in the implementeation language.
The solution was to set the association link as an attribute of the class, as suggested by #qwerty_so and this article:
class A:
def link(self, b):
self.a_b = A_B(self, b) # set attribute
class B:
pass
class A_B: # association class
def __init__(self, a, b):
self.a = a # association-owned
self.b = b # association-owned
b = B()
a = A()
a.link(b)
a.a_b.b # navigable
Related
We all know the following code is bad because of the use of global variable:
a = 3.14
def inc():
global a
a += 1
inc()
b = a
It is so bad that in python one has to intentionally declare global to "break" the ban. But in the name of OO, how come the code below is justified:
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
A_instance = A()
A_instance.inc()
b = A_instance.a
Within the scope of the class instance, isn't the member variable simply the same as global variable? "self" basically grant unrestricted access to all variable to any member function regardless the necessity, making it very stateful, prone to mistakes, and difficult to read (basically all the bad traits of global var)?
We also know the clean and better way is:
def inc(_a):
return _a+1
a = 3.14
b = inc(a)
So that the function inc() is at least stateless and has a predictable behavior. What's the best practice to use class and make it as stateless as possible? Or by definition, is OO always stateful and one has to go functional programming without classes at all? I also heard people say #static methods are stupid, break encapsulation, and should be avoided...
It comes down to whether you need to save state or not. If you do need to save state then it needs to be saved somewhere. Classes allow you to save state alongside the methods that operate on that state and enforce a class-local scope that is less error prone than storing state within a global scope.
As a concrete example, I recently implemented a Tree class for a forest simulation. One of the variables that is important to associate with a tree is its age. Where should the age of the tree be stored? It makes more sense to store it within the Tree class than outside of it.
If protecting the age of the tree from being manipulated by code outside of the class was important, I could have used Python's excellent #property syntax for that purpose, or less directly through the Python _varname variable naming convention.
Within the class, yes, the age of the tree is visible to the other methods, but that is a relatively narrow scope, certainly not akin to a global scope if your classes are written with a single responsibility in accord with SOLID object oriented design principles.
Now the reason why the concept of self is not considered bad practice is that if you are to create a class everything within that class ought to be related in one way or another which usually is class attributes that class instances are initialized with via the __init__ dunder method. Basically, if you are going to create a class then there ought to be a link of some sort, a class global if you will which are class attributes
usually the idea that creating classes with just self like this
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
is not something that is often seen, rather people chose the way which is generally in many opinions considered cleaner and more predictable
class A:
def __init__(self, a):
self.a = a
def inc(self):
self.a += 1
With this when you declare class instances you have more control of what is actually there, so class instances are hence declared with variables
A_instance = A(3.14) #a will be 3.14 in this instance
B_instance = A(3.142) #a will be 3.142 in this instance
and so on.
Class variables that are declared outside the __init__ function but inside the class, itself are considerably different and that would look like
class A:
a = 22/7
def __init__(self):
....
with this a would be a global variable throughout the class(not the instance but the class itself). So what does that look like
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
Although A_instance and B_instance are completely different and A_instance.item will equal 3.14 while B_instance.item will equal 5 both of these will have the class variable a as 22/7
A_instance.a #this will return a value of 22/7
B_instance.a #this will also return a value of 22/7
So the class variable remains consistent/the same throughout all instances of that class unless it is actively altered.
Point is if you are going to create a class it should have specific variables that are intertwined with each other and affect all a particular group of functions, these are the functions you make into class methods as such the use of self within classes is not wrong if used properly
I have a base class BaseClass with multiple subclasses SubClass1, SubClass2. In practice the program only works with instances of one of the sub-classes. The sub-classes implement an interface with the save method. When loading a saved element, you do not know the class you are loading. Therefore I was considering having the load method in the base class, but this raised the question: how do I instantiate an element from one of the sub-classes in the base class ?
For clarity, here is some simple code:
class BaseClass:
def load(self):
#load element of subclass
return subclass_element
class myInterface:
__metaclass__ = ABCMeta
#abstractmethod
def save(self):
raise NotImplementedError
class SubClass1(BaseClass, myInterface):
def save(self):
#save the element
class SubClass2(BaseClass, myInterface):
def save(self):
#save the element
I'm also open to any suggestions in favor of a different design. I'm not sure I'm not implementing an anti-pattern.
EDIT 1: Adding a factory class
From my understanding of what #Vishal_Raja and #Gholamali-Irani suggested:
class SubClassLoader: #this is our factory class
registered_subclasses = {} #static dict of subclasses
#StaticMethod
def register(classname, class):
SubClassLoader.registered_subclasses[classname] = class
#StaticMethod
def get_instance(filepath):
classname, arguments = get_classname(filepath)
if classname in SubClassLoader.registered_subclasses:
return SubClassLoader.registered_subclasses[classname](arguments)
else:
raise TypeError("Unknown class %s" % classname)
class BaseClass:
pass
class myInterface:
__metaclass__ = ABCMeta
#abstractmethod
def save(self):
raise NotImplementedError
class SubClass1(BaseClass, myInterface):
def save(self):
#save the element
class SubClass2(BaseClass, myInterface):
def save(self):
#save the element
First of all:It is bad design to make a dependency from parent to child. Inheritance (of child from parent) is a type of dependency. If you add another dependency from parent to child, you make a circular dependency and it's very hard to maintain and extendable.
In Object Oriented Design Heuristics we have:
Heuristic 5.1: Derived classes must have knowledge of their base class by definition,
but base classes should not know anything about their derived classes.
Why?
If base classes have knowledge of their derived classes, then it is
implied that if a new derived class is added to a base class, the code
of the base class will need modification. This is an undesirable
dependency between the abstractions captured in the base and derived
classes. We will see a much better solution to these types of
dependencies when we discuss the topic of polymorphism later in this
chapter. see reference
Therefore, it is bad design to put Load() into parent.
Secondly: you said:
when loading a saved element, you do not know the class you are loading.
So, your client only depend on Save() method. Therefore, their is not dependency between your client and parent. Your client only depend on the myIntrface.
Finally: your client should define an attribute from myInterface. Then you only need another class that inject the object to your client attribute. (like Factory class -as #VishalRaja's answer- or Dependency Injector class). Then you can put all desired configuration in it to decide which class instances should be passed.
Why don't you create a separate factory class which ensures the right save implementation depending on the subclass type?
If I add public method to subclass and a client program calls added method, client programs can't use parent object instead of subclass.
import unittest
class BaseClass(object):
def doSomething(self):
pass
class SubClass(BaseClass):
def doStuff(self):
pass
class Client(object):
def __init__(self, obj):
self.obj = obj
def do(self):
self.obj.doStuff()
class LSPTestCase(unittest.TestCase):
def test_call_subclass_method(self):
client = Client(SubClass())
client.do()
def test_call_baseclass_method(self):
client = Client(BaseClass())
with self.assertRaises(AttributeError):
client.do()
if __name__ == '__main__':
unittest.main()
This case violates LSP?
No as long as all the methods inherrited from the parent class follow the same contract as the parent then LSP is preserved.
the whole point of LSP is to be able to pass around a subclass as the parent class without any problems. It says nothing about not being able to downcast for additional functionality.
Adding a method to a subclass does not violate LSP. However, it does violate if you invoke that method by downcasting from a parent class.
Robert C. Martin states right in the beginning of his LSP / SOLID paper that:
select a function based upon the type of an object
(...) is an example of a simple violation of the Liskov Substitution Principle.
Generally, if you end up in situations where you need to downcast or use the instanceof operator, it's better to revisit the use of inheritance in favor of other approaches like composition.
If class B inherits from class A, does class B always have to be a sub-type of A when used in inheritance?
I am thinking if it is possible to use inheritance to provide extra code to B, when B is not a subtype of A?
If type A inherits from B, that means two things:
Class `A` will be able to use public and protected static methods from class `B`, without having to specify the class name, and objects of class `A` will implicitly include all public and protected class members from `B` without having to respecify them.
Any code accepting objects of type `B` will, at at compile time, accept objects of type `A`, and objects of class `A` will be able to use class `B`'s public and protected instance methods on themselves.
Interfaces essentially embody concept #2 but not #1 (since interfaces have no static methods, and have no members that can be used implicitly without having to specify them). There is no built-in way to achieve #1 without #2; the only significant benefit of having #1 without #2 would be to save typing.
If:
class B extends A
Than B is by definition a subtype of A.
If you don't want that, you can use PHP's traits, which is basically interfaces with implementation.
public class B {
public String getMe()
{
return "Some";
}
}
Assume that i have a above class , by which parameters should we decide what to use ?? Whether is a or Has a Relation ??
HAS - A
public class A {
public static void main(String args[])
{
B b = new B();
System.out.println(b.getMe());
}
}
or
public class A extends B
{
public static void main(String args[])
{
A b = new A();
System.out.println(b.getMe());
}
}
Depends on the logical relation. It just needs to make sense.
Example:
Lets say you have Animal classes.
So you have these classes: Animal, Dog, Cat , Leopard, Fur, Feet
Cat and Dog IS A Animal.
Leopard IS A Cat.
Animal HAS A Fur, Feet.
In a nutshell:
IS A relationship means you inherit and extend the functionality of the base class.
HAS A relationship means the class is using another class, so it has it as a member.
There are 4 types of relations possible :
Generalization (IS A) : Which is implemented using inheritance like you did above. It's used when class A has all the same feature of B and you want to add some more features. So you simply extend B and add the new features.
Aggregation (HAS A) : This is a bit weaker relation than generalization. You use this relation when the object of A owns objects of B or is composed of objects of B (may be among other objects of other classes). The first type is called shared aggregation, the second is called composition. In aggregation and composition there usually an object controlling the life of the other object (it instantiates it and destroys it as it needs).
Association: In association, the classes simply know about each other's so it's weaker than aggregation. The objects do not control each other's life.
Usage : It's the weakest relation of two classes and it means simply that one class may appear as a type in a method parameter or is used internally in code.
In your example, it should be aggregation (HAS A) if A has a field of type B. But if it just creates instance of B to be used in code internally and the object is disposed from memory when the scope ends then it's neither IS A nor HAS A. It's just a usage relation.
In simple term:
"is a" represent the inheritence/extends
"has a" represents the delegation/association
for example:
House is a Building (inheritance)
House has a door(s) (association)
Here is one of the best resources I used for understanding OOP: http://chortle.ccsu.edu/CS151/cs151java.html (part 6 & 10)
is-a is like for example, a Dog is an Animal or a Cat is an Animal or It is like "a person is that-kind of a person". Is-a relationships have other objects' properties, like here "Animal" is a class(object) and etc.
The has-a relationship is like, an object has its own properties, for example, Fish has Gills or pants have pockets ... something like that.