6
\$\begingroup\$

I have one application with two views. One to sign in and one to sign up. Each view has an Email entry as main identifier.

I want to add some itemTemplates to my application, because for now I repeat all UI properties twice.

In the code, a block is a listItem. Some blocks have the same name, but icons is different, and that's why I put it as an argument.

This is the new architecture I want to set up:

internal class SignUp : ViewModelBase
{
    private readonly List<object> _content = new List<object>();

    public SignUp()
    {
        _content.Add(BlockFactory.Create("Email"));
        _content.Add(BlockFactory.Create("Address"));
    }
}

internal class SignIn : ViewModelBase
{
    private readonly List<object> _content = new List<object>();

    public SignIn()
    {
        _content.Add(BlockFactory.Create("Email"));
    }
}

//So SignUp.Content[1].BlockItems.ElementAt(0) will be different to
// SignUp.Content[0].BlockItems.ElementAt(0)

public class BlockItem
{
    public bool IsVisible;
    public string Name;
    public string Template;
    public object Value;
}

public class Block
{
    public List<BlockItem> BlockItems = new List<BlockItem>();
    public string Icon;
    public string Name;

    public Block(string name, string icon)
    {
        Name = name;
        Icon = icon;
    }
}

public static class BlockFactory
{
    public static Block Create(string name)
    {
        switch (name)
        {
            case "Email":
                return new Block("Email", "")
                {
                    BlockItems = new List<BlockItem>
                    {
                        new BlockItem
                        {
                            Name = "Email",
                            Value = "",
                            IsVisible = true,
                            Template = "Entry"
                        }
                    }
                };
            case "Address":
                return new Block("Address", "")
                {
                    BlockItems = new List<BlockItem>
                    {
                        new BlockItem
                        {
                            Name = "Street",
                            Value = "",
                            IsVisible = true,
                            Template = "Entry"
                        },
                        new BlockItem
                        {
                            Name = "Zip",
                            Value = "",
                            IsVisible = true,
                            Template = "Entry"
                        },
                        new BlockItem
                        {
                            Name = "City",
                            Value = "",
                            IsVisible = true,
                            Template = "AnotherTemplate"
                        }
                    }
                };
        }
        return null;
    }
}

Is it possible to review my code and share possible improvements?

In the UI side, I'll have only one list with itemTemplate and based on the BlockItems.Count. I'll display elements in one line or more.

\$\endgroup\$
  • 2
    \$\begingroup\$ I edit and put some real code \$\endgroup\$ – tematim Feb 10 '17 at 16:39
  • \$\begingroup\$ This is much better ;-) \$\endgroup\$ – t3chb0t Feb 10 '17 at 16:42
1
\$\begingroup\$

Here is an example of where we could combine the Factory Pattern along with a Builder Pattern to extend your current code.

class SignUp : ViewModelBase
{
    private readonly List<Block> _content = new List<Block>();

    public SignUp()
    {
        _content.Add(BlockFactory.Create(BlockType.Email));
        _content.Add(BlockFactory.Create(BlockType.PostalAddress));
    }
}

class SignIn : ViewModelBase
{
    private readonly List<Block> _content = new List<Block>();

    public SignIn()
    {
        _content.Add(BlockFactory.Create(BlockType.Email));
    }
}

public static class BlockType
{
    public const string Email = "Email";
    public const string PostalAddress = "Postal Address";
}

public static class BlockFactory
{
    public static Block Create(string blockType)
    {
        if (String.IsNullOrEmpty(blockType)) throw new ArgumentNullException(nameof(blockType));

        switch (blockType)
        {
            case BlockType.Email:
                return new BlockBuilder()
                    .Name(BlockType.Email)
                    .Icon("email_icon.png")
                    .Build();
            case BlockType.PostalAddress:
                return new BlockBuilder()
                    .Name(BlockType.PostalAddress)
                    .Icon("postal_icon.png")
                    .Description("Give us your mailing address to get great stuff by postal mail!")
                    .BlockItems(
                        new List<BlockItem>()
                        {
                            new BlockItem() { Name = "Street", Value = "", IsVisible = true, template = "" },
                            new BlockItem() { Name = "Zip", Value = "", IsVisible = true, template = "" },
                            new BlockItem() { Name = "City", Value = "", IsVisible = true, template = "" }
                        })
                    .Build();
        }

        throw new ArgumentException("Invalid BlockType.");
    }
}

public class BlockItem
{
    public string Name;
    public object Value;
    public bool IsVisible;
    public string template;
}

public class Block
{
    public List<BlockItem> BlockItems = new List<BlockItem>();
    public string Name;
    public string Icon;
    public string Description;
}

public class BlockBuilder
{
    private List<BlockItem> _blockItems;
    private string _name;
    private string _icon;
    private string _description;

    public BlockBuilder BlockItems(List<BlockItem> value)
    {
        _blockItems = value;
        return this;
    }

    public BlockBuilder Name(string value)
    {
        _name = value;
        return this;
    }

    public BlockBuilder Icon(string value)
    {
        _icon = value;
        return this;
    }

    public BlockBuilder Description(string value)
    {
        _description = value;
        return this;
    }

    public Block Build()
    {
        return new Block
        {
            BlockItems = _blockItems,
            Name = _name,
            Icon = _icon,
            Description = _description
        };
    }
}

If you don't like the constants for the BlockType, you can remove this part, but I tend to lean towards easier refactoring instead of using "hand-coded" strings to pass into factories.

public static class BlockType
{
    public const string Email = "Email";
    public const string PostalAddress = "Postal Address";
}

The reason for Builders, is that you can really get good mileage on your class as you need to expand it with more properties and not have to write so many parameter overrides, etc.

For example you could do this in the future with relative ease and straight-forward implementation.

Block block = new BlockBuilder()
            .Name(BlockType.Email)
            .Icon("email_icon.png")
            .Template(...)
            .Styling(...)
            .CloseEventHandler(...)
            .OpenEventHandler(...)
            .Preloader(...)
            .Build();
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Nice solution, I'll start from your code to create my new architecture \$\endgroup\$ – tematim Feb 10 '17 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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