17

Imagine your customer want's to have a possibility to add new property (e.g. color) to product in their eshop in their CMS.

Instead of having properties as fields:

class Car extends Product {
   protected String type;
   protected int seats;
}

You would probably end up doing something like:

class Product {
   protected String productName;
   protected Map<String, Property> properties;
}

class Property {
   protected String name;
   protected String value;
}

That is, creating own type system on top of existing one. It feels to me like this could be seen as creating domain specific langauge, or couldn't?

Is this approach a known design pattern? Would you solve the problem differently? I know there are languages where I can add a field in runtime, but what about database? Would you rather add/alter columns or used someting as shown above?

Thank you for your time :).

7
  • 3
  • Not sure what language you are using, but if it is C# you could use a dynamic type which basically stores a KVP in a dictionary kinda like what you are doing on products and allows you to just tack on properties without having to directly add them to the collection as a collection. You will not have strong typing though. I know you asked for a design pattern but I don't feel you would need anything complex to use them. msdn.microsoft.com/en-us/magazine/gg598922.aspx
    – Tony
    Commented Apr 18, 2014 at 12:51
  • Tony: I'm using Java here, but consider it pseudo coude :). Would C# allow me to persist that dynamic object into database? I doubt it, as databse needs to know structure of data up front.
    – Filip
    Commented Apr 18, 2014 at 16:53
  • There is the State Desing Pattern a-la Gang-of-Four, which makes an object appear to change its type or class at run-time. Other alternatives are Observer Design Pattern or a Proxy Design Pattern
    – Nikos M.
    Commented May 23, 2014 at 13:46
  • 1
    Why not just use map datatype? In DB it may be represented as {id} + {id, key, value}, if you not asking for performance. Commented Jul 9, 2014 at 5:08

4 Answers 4

5

Congratulations! You have just circumnavigated the programming language / type system globe, arriving on the other side of the world from whence you departed. You have just landed on the border of dynamic language / prototype-based object land!

Many dynamic languages (e.g. JavaScript, PHP, Python) allow one to extend or change object properties at runtime.

The extreme form of this is a prototype based language like Self or JavaScript. They do not have classes, strictly speaking. You can do things that look like class-based, object-oriented programming with inheritance, but the rules are greatly relaxed compared to more sharply-defined, class-based languages like Java and C#.

Langauges like PHP and Python live in the middle ground. They have regular, idiomatic class-based systems. But object attributes can be added, changed, or deleted at runtime--albeit with some restrictions (like "except for built-in types") that you don't find in JavaScript.

The big tradeoff for this dynamism is performance. Forget how strongly or weakly typed the language is, or how well it can be compiled down to machine code. Dynamic objects must be represented as flexible maps/dictionaries, rather than simple structs. This adds overhead to every object access. Some programs go to great lengths to reduce this overhead (e.g. with phantom kwarg assignment and slot-based classes in Python), but the extra overhead is usually just par for the course and the price of admission.

Getting back to your design, you're grafting the ability to have dynamic properties onto a subset of your classes. A Product can have variable attributes; presumably an Invoice or an Order would and could not. It's not a bad way to go. It gives you the flexibility to have variation where you need it, while remaining in a strict, disciplined language and type system. On the down side, you are responsible for managing those flexible properties, and you'll probably have to do so through mechanisms that look slightly different from more native attributes. p.prop('tensile_strength') rather than p.tensile_strength, for instance, and p.set_prop('tensile_strength', 104.4) rather than p.tensile_strength = 104.4. But I've worked with and built many programs in Pascal, Ada, C, Java and even dynamic languages that used exactly such getter-setter access for non-standard attribute types; the approach is clearly workable.

By the by, this tension between static types and a highly varied world is extremely common. An analogous problem is often seen when designing database schema, especially for relational and pre-relational data stores. Sometimes it's dealt with by creating "super-rows" that contain enough flexibility to contain or define the union of all imagined variations, then stuffing any data that comes along into those fields. The WordPress wp_posts table, for example, has fields like comment_count, ping_status, post_parent and post_date_gmt that are only interesting under some circumstances, and that in practice often go blank. Another approach is a very spare, normalized table like wp_options, much like your Property class. While it requires more explicit management, items in it are rarely blank. Object-oriented and document databases (e.g. MongoDB) often have an easier time dealing with changing options, because they can create and set attributes pretty much at will.

0

I like the question, my two cents:

Your two approaches are radically different:

  • The first one is OO ans strongly typed - but not extensible
  • The second one is weakly typed (string encapsulates anything)

In C++, many would use a std::map of boost::variant to achieve a mix of both.

Disgression: Note that some languages, such as C#, allows the dynamic creation of types. Which could be a nice solution for the general issue of adding members dynamically. However, "modifying/adding" types after compilation does corrupt the type system itself, and makes your "modified" types almost useless (e.g., how would you access such added properties, since you dont even know they exists ? The only reasonable way would be a systematic reflection over each object ... ending with a pure dynamic language _ you can refer to the 'dynamic' .NET keyword)

1
  • Creating types at runtime seams interesting but too exotic for me (I'm programming in Java). Such solution would not work, if I would want to store object in databse, which is always strongly typed I belive. The weakly typed solution I have proposed can be stored in database easily.
    – Filip
    Commented Apr 18, 2014 at 8:42
0

Creating a type at runtime sounds much more complicated then just creating an abstraction layer. It is very common to create an abstraction to decouple systems.

Let me show an example from my practice. Moscow exchange has the trading core called Plaza2 with trader's API. Traders write their programs to work with financial data. The problem is that this data is very huge, complex, and highly exposed to changes. It can change after a new financial product introduced or rools of clearing changed. Nature of future changes can not be predicted. Literally, it can change every day and poor programmers should edit the code and release a new version, and angry traders should revise their systems.

Obvious decision is to hide all financial hell behind an abstraction. They've used well known SQL tables abstraction. Biggest part of their core can work with any valid schema, the same as trader's software can dynamically parse the schema and find out whether it is compatible with their system.

Returning back to your example, it is normal to create an abstract language in front of some logic. It could be "property", "table", "message", or even human language, but pay attention to the drawbacks of this approach:

  • More code for parsing and validating (and more time off course). Everything what compiler did for you with static typing you must do in the run-time.
  • More documentation of messages, tables or other primitives. All the complexity goes from code to some sort of schema or standart. Here is an example of above-mentioned financial hell schema: http://ftp.moex.com/pub/FORTS/Plaza2/p2gate_en.pdf (dozens of pages of tables)
0

Is this approach a known design pattern?

In XML and HTML, these would be the attributes to a node/element. I've also heard them called extended properties, name/value pairs, and parameters.

Would you solve the problem differently?

That is how I would solve the problem, yes.

I know there are languages where I can add a field in runtime, but what about database?

A database would be like Java, in some senses. In pesudo-sql:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

This would correspond to the Java

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Note that there is no need for a Property class, as the Map stores the name as the key.

Would you rather add/alter columns or used someting as shown above?

I've tried the add/alter column thing, and it was a nightmare. It can be done, but things kept getting out of sync and I never got it to work well. The table structure I outlined above has been much more successful. If you need to do searches and order by's, consider using an attributes table for each data type (date_attributes, currency_attributes, etc.) or adding some of the properties as good old database columns in the products table. Reports are often much easier to write on database columns then sub tables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.