xinthink/react-native-material-kit

[Question] - Builder versus configuration object

jaygarcia opened this issue ยท 8 comments

Question as to why you used the builder pattern instead of a configuration object pattern for configuring instances.

The following has ten total method calls just for one button.

var CustomButton = new MKButton.Builder()
  .withBackgroundColor(MKColor.Teal)
  .withShadowRadius(2)
  .withShadowOffset({width:0, height:2})
  .withShadowOpacity(.7)
  .withShadowColor('black')
  .withOnPress(() => {
    console.log('hi, raised button!');
  })
  .withTextStyle({
    color: 'white',
    fontWeight: 'bold',
  })
  .withText('RAISED BUTTON')
  .build();

The MooTools configuration pattern uses just one

var CustomButton = new MKButton({
    backgroundColor : MKColor.Teal,
    shadow : {
        radius  : 2,
        opacity : .7,
        color   : 'black',
        offset  : {
            width  : 0,
            height : 2
        }
    },
    textStyle {
        color      : 'white',
        fontWeight : 'bold'
    },
    onPress : () => {
        console.log('onPress')
    }

});

Hi @jaygarcia, thanks for the valuable question.

The same question has been frustrating me ๐Ÿ˜–, until I realize that I'm not going to obsolete the object pattern by introducing builder. I just can't, configuration object is built into the heart of ES7 (Object Spread) and thus React (Props Transferring). For example, you're always free to do this:

var coloredButtonProps = {
  style: {
    marginLeft: 20,
    marginRight: 20,
  },
  backgroundColor: MKColor.Purple,
  rippleLayerColor: MKColor.Lime,
  onPress: () => console.log('button clicked'),
};

var buttonTextProps = {
  pointerEvents: 'none',
  style: {
    color: 'white',
    fontWeight: 'bold',
  },
};

<MKButton {...coloredButtonProps}>
  <Text {...buttonTextProps}>
    Halo!
  </Text>
</MKButton>

the props objects can be reused & extended:

var accentButtonProps = {
  ...coloredButtonProps,
  backgroundColor: MKColor.DeepOrange,
};

<MKButton {...accentButtonProps}>
  <Text {...buttonTextProps}>
    Accent colored raised button
  </Text>
</MKButton>

So, my reasoning is that the builder is just another way to make and reuse view definitions, hoping those who feel familiar to builder pattern or method chaining will like it.

An additional reason to introduce builder pattern is that it can make the best out of IDE's code completion feature (e.g. WebStorm).
ide-code-completion

It is not an either-or situation, you can even mix them up, to leverage the pre-defined theme:

var accentButtonProps = {
  ...MKButton.coloredButton().toProps(),
  backgroundColor: MKColor.DeepOrange,
};

<MKButton {...accentButtonProps}>
  <Text {...buttonTextProps}>
    Accent colored raised button
  </Text>
</MKButton>

Hope my choice is reasonable, ๐Ÿป. I'll leave this issue open in case of someone interested wanna join the discussion.

Hi! Thanks for great thing.
How to create fab in JSX code?

the most easy way is to leverage the predefined props:

var coloredFabProps = {
  ...MKButton.coloredFab().toProps(),
  style: {
    width: 42, height: 42,
  },
  cornerRadius: 21,
};

<MKButton {...coloredFabProps}>
  <Image pointerEvents="none" source={require('image!plus-white')} />
</MKButton>

if you prefer the tag style

<MKButton
  shadowRadius={2}
  shadowOffset={{width: 0, height: 2}}
  shadowOpacity={.7}
  style={{
    backgroundColor: MKColor.Indigo,
    width: 42,
    height: 42,
  }}
  cornerRadius={21}
  >
  <Image pointerEvents="none" source={require('image!plus-white')} />
</MKButton>

Can we have more documentation on the standard configuration object style ? I think patterns like the builder pattern are more useful in statically typed languages.

hi @Sherlock92, maybe you're right about builder, but it's not mandatory, like I said, you're free to use React-style props.
About documents, how do u think about the annotated source?

@xinthink great, I somehow missed these docs. Thanks so much!

It would be great to able to combine the approaches. So use the builder pattern to configure widgets that you will use then be able to customise them at runtime using props. I know you can do this with some props but not all.

Specifically Text doesn't work, I'm not sure about other props yet.

@slonoed previously asked how to create the fab using tag style. If you use MKButton as was shown in the example, you actually still need to pass a prop of fab={true} otherwise onPress the nice spreading effect onPress will outline as a square.