Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Friday, May 11, 2018

How should I design a set of related classed where only some of them support a certain operation?

Leave a Comment

I am working on a slide-based application in C++. Each slide has a slide-items collection which can include items like caption, button, rectangle, etc.

Only some of these items support fill, while others don't.

What is the best way to implement the fill for the slide items in this case? Here are two ways that I thought of:

  1. Create an interface Fillable and implement this interface for slide items which support fill, keeping all the properties related to fill in the interface. When iterating over the list of slide items, dynamic_cast them into Fillable, and if successful, do the operation related to fill.

  2. Make a fill class. Make a fill pointer a part of slide item class, assign the fill object to the fill pointer for those objects which support fill, and for rest of them keep it null. Give a function GetFill, which will return the fill for the items if it exists otherwise returns NULL.

What's the best approach for this? I'm interested in performance and maintainability.

6 Answers

Answers 1

I would do a combination of the two. Make your Fillable interface and have it be the return type for your GetFill method. This is better than the dynamic cast approach. Using dynamic cast to query for the interface requires that the actual slide item object implement the interface if it is to support it. With an accessor method like GetFill however, you have the option of providing a reference/pointer to some other object that implements the interface. You can also just return this if the interface is in fact implemented by this object. This flexibility can help avoid class bloat and promote the creation of re-usable component objects that can be shared by multiple classes.

Edit: This approach also works nicely with the null object pattern. Instead of returning a null pointer for the objects that don't support Fillable, you can return a simple no-op object that implements the interface. Then you don't have to worry about always checking for null pointers in the client code.

Answers 2

The answer is it depends.

I don't see the point in having to clutter your base interface with fill/get_fillable_instance/... if not every object is supposed to handle fill. You can however get away with just

struct slide_object {     virtual void fill() {} // default is to do nothing }; 

but it depends on whether you think fill should appear in the slide object abstract class. It rarely should however, unless being non fillable is exceptional.

Dynamic casting can be correct in the case you need to provide two distinct classes of objects (and no more than two), some of them being fillable, and the other having nothing to do with fillability. In this case, it makes sense to have two sub-hierarchies and use dynamic casting where you need.

I have used this approach successfully in some cases and it is simple and maintainable, provided the dispatch logic is not scattered (ie. there is only one or two places where you dynamic cast).

If you are expected to have more fill-like behavior, then dynamic_cast is a wrong choice since it will lead to

if (auto* p = dynamic_cast<fillable*>(x))    ... else if (auto* p = dynamic_cast<quxable*>(x))    ... 

which is bad. If you are going to need this, then implement a Visitor pattern.

Answers 3

Create a base class SlideItem:

class SlideItem {     public:         virtual ~SlideItem();         virtual void fill() = 0; }; 

Then do an empty implementation for those you can't fill:

class Button : public SlideItem {     public:         void fill() { } }; 

And a proper fill implementation for the others:

class Rectangle : public SlideItem {     public:         void fill() { /* ... fill stuff ... */ } }; 

and put all of them inside a container.. if you want to fill them just call everybody... easy to maintain.. and who cares about performance :)


If you really need fast code your first solution is certainly good. But if you do it like that, make sure you don't have to cast it every time you want to fill. Cast them one time and put the pointers in a fillable-container. Then iterate over this fillable-container if you have to fill.

Then again, IMHO you put too much effort into this, without a reasonable performance gain. (of course I don't know your application, it might be justified.. but usually not)

Answers 4

It seems like what you're looking for is close to the Capability Pattern. Your #2 is close to this pattern. Here's what I would do:

Make a fill class. Make fill pointer a part of slide item class, assign the fill object to fill pointer for only those objects which support fill, for rest of them keep it null. Create a function GetCapability(Capability.Fill), which will return the fill for the items if it exists otherwise returns NULL. If some of your objects already implement a Fillable interface, then you can return the object cast to a Fillable pointer instead.

Answers 5

Consider storing Variant items, such as boost::variant.

You can define a boost::variant<Fillable*,Item*> (you should use smart pointers if you have ownership), and then have a list of those variants on which to iterate.

Answers 6

I suggest using an interface for the shapes, with a method that returns a filler. For example:

class IFiller { public:     virtual void Fill() = 0;  protected:     IFiller() {}     virtual ~IFiller() {} };  class IShape { public:     virtual IFiller* GetFiller() = 0;  protected:     IShape() {}     virtual ~IShape() {} };  class NullFiller : public IFiller { public:     void Fill() { /* Do nothing */ } };  class Text : public IShape { public:     IFiller* GetFiller() { return new NullFiller(); } };  class Rectangle; class RectangleFiller : public IFiller { public:     RectangleFiller(Rectangle* rectangle) { _rectangle = rectangle; }     ~RectangleFiller() {}      void Fill() { /* Fill rectangle space */ }  private:     Rectangle* _rectangle; };  class Rectangle : IShape { public:     IFiller* GetFiller() { return new RectangleFiller(this); } }; 

I find this method easier to maintain and to extend, while it does not introduce major performance issues.

Read More

Sunday, October 8, 2017

Define an algorithm which gets a number and a list and returns a scalar based on number's distance to average of the list

Leave a Comment

Let's suppose that we have got a list which appends an integer in each iteration which is between 15, 32(let's call the integer rand). I want to design an algorithm which assigns a reward around 1 (between 1.25 and 0.75) to each rand. the rule for assigning the reward goes like this.

first we calculate the average of the list. Then if rand is more than average, we expect the reward to be less than 1, and if rand is less than average, the reward gets higher than 1. The more distance between average and rand, the more reward increases/decreases. for example:

rand = 15, avg = 23 then reward = 1.25

rand = 32, avg = 23 then reward = 0.75

rand = 23, avg = 23 then reward = 1 and so on.

I had developed the code below for this algorithm:

import numpy as np  rollouts = np.array([]) i = 0  def modify_reward(lst, rand):   reward = 1   constant1 = 0.25   constant2 = 1    std = np.std(lst)   global avg   avg = np.mean(lst)   sub = np.subtract(avg, rand)   landa = sub / std if std != 0 else 0   coefficient =  -1 + ( 2 / (1 + np.exp(-constant2 * landa)))   md_reward = reward + (reward * constant1 * coefficient)   return md_reward  while i < 100:   rand = np.random.randint(15, 33)   rollouts = np.append(rollouts, rand)   modified_reward = modify_reward(rollouts, rand)   i += 1   print([i,rand, avg, modified_reward])  # test the reward for upper bound and lower bound  rand1, rand2 = 15, 32 reward1, reward2 = modify_reward(rollouts, rand1), modify_reward(rollouts, rand2)  print(['reward for upper bound', rand1, avg, reward1]) print(['reward for lower bound', rand2, avg, reward2]) 

The algorithm works quite fine, but if you look at examples below, you would notice the problem with algorithm.

rand = 15, avg = 23.94 then reward = 1.17 # which has to be 1.25

rand = 32, avg = 23.94 then reward = 0.84 # which has to be 0.75

rand = 15, avg = 27.38 then reward = 1.15 # which has to be 1.25

rand = 32, avg = 27.38 then reward = 0.93 # which has to be 0.75

As you might have noticed, Algorithm doesn't consider the distance between avg and bounds (15, 32). The more avg moves towards lower bound or higher bound, the more modified_reward gets unbalanced.

I need modified_reward to be uniformly assigned, no matter avg moves toward upper bound or lower bound. Can anyone suggest some modification to this algorithm which could consider the distance between avg and bounds of the list.

4 Answers

Answers 1

I don't understand why you are calculating md_reward like this. Please provide logic and reason. But

landa = sub / std if std != 0 else 0 coefficient =  -1 + ( 2 / (1 + np.exp(-constant2 * landa))) md_reward = reward + (reward * constant1 * coefficient) 

will not give what you are looking for. Because lets consider below cases

for md_reward to be .75  -->  coefficient should be -1     -->  landa == -infinite (negative large value, i.e. , rand should be much larger than 32)  for md_reward to be 1 -->  coefficient should be 0     -->  landa == 0 (std == 0 or sub == 0) # which is possible  for md_reward to be 1.25  -->  coefficient should be 1     -->  landa == infinite (positive large value, i.e. , rand should be much smaller than 15) 

If you want to normalize reward from avg to max and avg to min. check below links. https://stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range https://stats.stackexchange.com/questions/70553/what-does-normalization-mean-and-how-to-verify-that-a-sample-or-a-distribution

Now modify your function with something below.

def modify_reward(lst, rand):     reward = 1     constant1 = 0.25     min_value = 15     max_value = 32     avg = np.mean(lst)     if rand >= avg:         md_reward = reward - constant1*(rand - avg)/(max_value - avg) # normalize rand from avg to max     else:         md_reward = reward + constant1*(1 - (rand - min_value)/(avg - min_value)) # normalize rand from min to avg     return md_reward 

I have used below method

Normalized: (X−min(X))/(max(X)−min(X)) 

for case rand >= avg

min(X) will be avg and max(X) is max_value

and for case rand < avg

min(X) in min_value and max(X) is avg

Hope this helps.

Answers 2

Putting together these two requirements:

if rand is more than average, we expect the reward to be less than 1, and if rand is less than average, the reward gets higher than 1.

I need modified_reward to be uniformly assigned, no matter avg moves toward upper bound or lower bound.

is slightly tricky, depending on what you mean by 'uniformly'.

If you want 15 to always be rewarded with 1.25, and 32 to always be rewarded with 0.75, you can't have a single linear relationship while also respecting your first requirement.

If you are happy with two linear relationships, you can aim for a situation where modified_reward depends on rand like this:

enter image description here

which I produced with this Wolfram Alpha query. As you can see, this is two linear relationships, with a 'knee' at avg. I expect you'll be able to derive the formulae for each part without too much trouble.

Answers 3

This code implements a linear distribution of weights proportional to the distance from average towards your given limits.

import numpy as np  class Rewarder(object):     lo = 15     hi = 32     weight = 0.25      def __init__(self):         self.lst = np.array([])      def append(self, x):         self.lst = np.append(self.lst, [x])      def average(self):         return np.mean(self.lst)      def distribution(self, a, x, b):         '''             Return a number between 0 and 1 proportional to              the distance of x from a towards b.             Note: Modify this fraction if you want a normal distribution             or quadratic etc.         '''         return (x - a) / (b - a)      def reward(self, x):         avg = self.average()          if x > avg :             w = self.distribution(avg, x, self.hi)         else:             w = - self.distribution(avg, x, self.lo)          return 1 - self.weight * w  rollouts = Rewarder() rollouts.append(23) print rollouts.reward(15) print rollouts.reward(32) print rollouts.reward(23) 

Producing:

1.25 0.75 1.0 

The code in your question seems to be using np.std which I presume is an attempt to get a normal distribution. Remember that the normal distribution never actually gets to zero.

If you tell me what shape you want for the distribution we can modify Rewarder.distribution to suit.

Answers 4

Try this

def modify_reward(lst, rand):     reward = 1     constant = 0.25 #Think of this as the +/- amount from initial reward      global avg     avg = np.mean(lst)     sub = np.subtract(avg, rand)     dreward = 0     if sub>0:         dreward = sub/(avg-15) #put your lower boundary instead of 15     elif sub<0:         dreward = sub/(32-avg) #put your higher boundary instead of 32     md_reward = reward +(dreward*constant)     return md_reward 

This is the linear solution inspired by @AakashM. I don't know if this is what you were looking for, but this fits your description.

Read More

Monday, June 26, 2017

Improving the design of a JPA polymorphic association

Leave a Comment

I have the following JPA entity hierarchy:

class diagram for jpa entities

Upon logging in to the application a user has an instance of UserAccount in session; then depending on the concrete type of the organization associated to that UserAccount (Admin, Business or Family), a different dashboard/screen is displayed to the user e.g. if the user is a Business, then the dashboard for that business is displayed.

My concern with that design is that I have to do a instanceof check each time a user logs in so that I know which type of dashboard to display. I could also avoid that instanceof check by having a property in UserAccount such as organizationType (which would take one of three values) but then there would be redundant information.

Is there a way to improve my design? If so how?

1 Answers

Answers 1

Be greedy and get both, without redundancy.

Depending on the inheritance strategy, you may already have the organizationType info and you can expose it for free.

@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "DTYPE") public abstract class AbstractOrganization implements Serializable {     @Id     protected Long id;      @Column(name = "DTYPE", insertable = false, updatable = false)     protected String organizationType;      ...  } 

the same applies also to the JOINED strategy.

Do not implement the setOrganizationType method.

Since a discriminator is required for simulating hierarchies with tables (except TABLE_PER_CLASS strategy), there's no redundancy and JPA provider will handle this attribute for you.

Read More

Tuesday, April 11, 2017

designing complex data structure's dependences

Leave a Comment

I'm in the process of designing a finite element library. For a given problem, the finite element mesh used can have elements of different dimensions (for example tetrahedra and triangles), and combining different elements of the same dimension is also possible (for example tetrahedra and hexahedra). Therefore, I need a data structure that stores the finite elements' information. The most fundamental information is the elements' connectivity (the node IDs that define the element). For example, I need to store somehow that triangular element 4 is connected to nodes 5, 6, and 10.

My first attempt was to create a list whose index is the dimension (0,1,2 or 3) and that stores dictionaries. These dictionaries have string keys (identifiers) and the values are numpy arrays (each row representing an element connectivity). I need to do this because the numpy arrays for a given dimension have different shapes depending on the string identifiers.

This is the class:

import os from collections import OrderedDict import numpy.ma as ma  flatten = lambda l: [item for sublist in l for item in sublist]  class ElementData(list):      def __init__(self, *args, **kwargs):          self.reset()         super(ElementData, self).__init__(*args, **kwargs)      def __iter__(self):         for k, v in self[self.idx].items():             for i, e in enumerate(v):                 yield (k,i,e) if not ma.is_masked(e) else (k,i, None)         self.reset()       def __call__(self, idx):         self.idx = idx-1         return self      def __getitem__(self, index):         if index >= len(self):             self.expand(index)         return super(ElementData, self).__getitem__(index)      def __setitem__(self, index, value):         if index >= len(self):             self.expand(index)         list.__setitem__(self, index, value)      def __str__(self):         return "Element dimensions present: {}\n".format([i for i in range(len(self)) if self[i]]) + super(ElementData, self).__str__()      def keys(self):         return flatten([list(self[i].keys()) for i in range(len(self))])      def reset(self):         self.idx = -1         self.d = -1      def expand(self, index):         self.d = max(index, self.d)         for i in range(index + 1 - len(self)):             self.append(OrderedDict())      def strip(self, value=None):         if not callable(value):             saved_value, value = value, lambda k,v: saved_value         return ElementData([OrderedDict({k:value(k, v) for k,v in i.items()}) for i in super(ElementData, self).__iter__()])       def numElements(self, d):          def elementsOfDimension(d):             # loop over etypes             nelems = 0             for v in self[d].values():                 nelems += v.shape[0] if not isinstance(v, ma.MaskedArray) else v.shape[0] - v.mask.any(axis=1).sum()             return nelems          # compute the number of all elements         if d == -1:             nelems = 0             for i in range(self.d+1):                 nelems += elementsOfDimension(i)             return nelems         else: # of specific dimension only             return elementsOfDimension(d) 

The class works nicely, and it allows me to loop seamlessly through all items of a particular dimension. However, there are other data associated with each element that's stored separately, for example its material. Therefore, I decided to use the same data structure to refer to other properties. To that end I use the strip function of the class, to return me the entire structure without the numpy arrays.

The problem that I is that the original data structure is dynamic, and if I change it, I have to modify every other structure that depends on it. I really think I went in the wrong direction while designing this class. Perhaps there's a simpler way to approach this problem? I thought about storing the extra information next to the numpy arrays (as tuples for example), but I don't know whether this is good or not. The choices made while designing software can really make our life miserable later, and I'm starting realize this now.

UPDATE

Using the class above, one example could be the following:

Element dimensions present: [0, 1, 2] [OrderedDict([('n1', array([[0],        [1],        [3]]))]), OrderedDict([('l2', array([[1, 2]]))]), OrderedDict([('q4', array([[0, 1, 5, 4],        [5, 1, 2, 6],        [6, 2, 3, 7],        [7, 3, 0, 4],        [4, 5, 6, 7]]))])] 

where the data structure has been used to store elements of 0 (node), 1 (line) and 2 (quadrangles) dimensions.

2 Answers

Answers 1

When said "Complex data structure's dependences", you probably may speak about "graph", did you double check if any existing graph theory fit your needs ? (like "Route problems")

Answers 2

Comment: the design goes against the logical structure of the program.

I used the given Element data example and didn't expect to get the whole picture at once.

Comment: Each element has a unique dimension (a triangle has always dimension 2, as a tetrahedron has always dimension 3 and a node dimension 0).

Sorry, I misinterpreted from the question "... elements of different dimensions..." with "Element have different dimensions". I adapted my Proposal.

Comment: ... the problem arises when I modify the data structure (for example by adding elements)

As long as you don't show a Data example for this problem, I can't thinking above a solution.


My Proposal:

class Dimension(object):     """     Base class for all Dimensions     Dimension has no knowledge to what the data belongs to     """     def __init__(self, data=None):         pass  class Element(object):     """     Base class for all Elements     Hold on class Dimension(object):     """     def __init__(self, dimension=None):         pass  class Triangle(Element):     def __init__(self, dimension):         super().__init__(dimension=dimension)  class Tetrahedron(Element):     def __init__(self, dimension):         super().__init__(dimension=dimension)  class Node(Element):     def __init__(self, dimension):         super().__init__(dimension=dimension) 

Usage: Building your example Element

node = Node(dimension=[0,1,3]) line = Triangle(dimension=[0,2]) quad = Tetrahedron(dimension=[[0, 1, 5, 4], [5, 1, 2, 6], [6, 2, 3, 7], [7, 3, 0, 4], [4, 5, 6, 7]]) 

New Future Element, only to show class Element could extended:

# New future dimensions - No changes to class Element() required class FutureNodTriTet(Element):     def __init__(self, dimension):         super().__init__(dimension=dimension)  future_NTT = FutureNodTriTet(dimension=[0, (1,3), (4,5,6)]) 

Please comment if this is closer to your needs.

Read More

Friday, March 18, 2016

design from ltr to rtl automatically

Leave a Comment

I am a French website that is in LFR (Left to Right) And the client is wanting to translate the site in hebrew thus transforming it to RTL (Right to Left). In all Hebrew Website the design is reversed

https://he.wikipedia.org/wiki/

https://www.google.co.il/

Is there a way to do this automatically ? Again I am not talking about the text direction. I want to flip it horizontally the design, like a mirror effect.

1 Answers

Answers 1

Your mileage may vary. Some web page generation tools support RTL with easy switch, while with others the WYSIWYG breaks completely when you specify <html dir="rtl">. Browser fragmentation may also be an issue: some browser simply don't support RTL bulleted lists correctly.

There are quite a few good tutorials on the Web; I would recommend https://hacks.mozilla.org/2015/09/building-rtl-aware-web-apps-and-websites-part-1/ and https://hacks.mozilla.org/2015/10/building-rtl-aware-web-apps-websites-part-2/. If you look up Google to search for more articles, please remember that this field is quickly changing, and some recipes of few years ago may be obsolete.

You may find the automation with css-flip or rtlcss useful.

Note that localization is generally not easy, and invariably requires a manual touch. You must understand the target culture very well to recognize tiny glitches that may look awful to the end-user. For example, on Hebrew Website you need different image for the "back" button. On Arabic sites, some numbers should be represented by indic digits, but other numbers are expected to use the usual digits.

Issues of first day of week, etc. are common for LTR localizations, too.

Read More