5
\$\begingroup\$

Today I thought about Factory Design Pattern in Swift, and I do an implementation with Extension.

My post is about if anyone have any observation or issue about this implementation violate any convention about Factories? Can I do this way?

I did it because I thought the statics function in my object not smell good, and for who will do maintenance it will confuse, and because this I split to Extension.

    let kToastMessageTurnType:String = "kToastMessageTurnType";
    let kWhoStartTheGameMessageType:String = "kWhoStartTheGameMessageType";

    class ToastMessage {

        private var gameState:GameState;

        private(set) var message:String = "";
        private(set) var isFoul:Bool = false;

        init(gameState:GameState, type:String, isFoul:Bool)
        {
            self.gameState = gameState;
            self.isFoul = isFoul;

            self.message = processMessage(type)
        }

        private func processMessage(type:String)->String
        {
            let textLocalized:TextLocalized;

            switch type
            {
            case GSFoulTypeBallEightPocketedInBreakShot:
                textLocalized = TextStartedIncorrectly(playersInfo: self.gameState);
            case GSFoulTypeBreakAtLeastFourBumpers:
                textLocalized = TextStartedIncorrectly(playersInfo: self.gameState);
             case kToastMessageTurnType:
                textLocalized = TextTurnMessage(playersInfo: self.gameState);
             case kWhoStartTheGameMessageType:
                textLocalized = TextWhoStartMessage(playersInfo: self.gameState);   
            default:
                return "";
            }

            return textLocalized.text
        }
    }
    //Factory from ToastMessage
    extension ToastMessage
    {
        class func getFoulToastMessage(type:String)->ToastMessage
        {
            return ToastMessage(gameState: GameState.shared, type: type, isFoul: true);
        }

        class func getNotifyTurnMessagetMessage()->ToastMessage
        {
            return ToastMessage(gameState: GameState.shared, type: kToastMessageTurnType, isFoul: false);
        }

        class func getWhoStartTheGameMessage()->ToastMessage
        {
            return ToastMessage(gameState: GameState.shared, type: kWhoStartTheGameMessageType, isFoul: false);
        }
    }
\$\endgroup\$
8
\$\begingroup\$

I can't recommend these string constants at all. We should be using an enum. Even if your enum is still string backed (which it doesn't appear that that'd be necessary), it's still going to be better overall to use an enum.

As a start, the enum, means that users can't simply pass any random value in. The values they can select from are more clearly defined. Auto-complete will give them a hint at their choices.

It's also more efficient. Despite the enum being back by a string, the actual value you're passing around isn't a string at all. The string is only ever accessed if you call RawValue on the enum value. This means all your enum comparisons (and switch statements) are all more efficient.

But the most important thing about using an enum here is that it might completely eliminate the need for your factory methods extension.

GameState is apparently a singleton accessed via the .shared property. You haven't provided enough context for me to take a stab at the idea of this being a singleton (maybe/probably unnecessary), but if it is a singleton, why does it need to be passed around, rather than just accessing it directly where ever it's needed? That sort of defeats the point of a singleton.

Likewise, we're not provided enough information about isFoul: and what that's supposed to mean.

But the point is GameState can definitely be eliminated from the initializer. And if we turn the type from a String to an enum with limited options, then the factory extension just seems completely unnecessary, because the init method is simple enough.

\$\endgroup\$
  • \$\begingroup\$ Your answer will be very important for my refactor in this code, Thanks @nhgrif. \$\endgroup\$ – ViTUu Apr 15 '15 at 22:10
  • \$\begingroup\$ In this case I can eliminate the Factory with Enuns, but use Factory with extension is a good way to do? What do you think about this implementation for Factory? \$\endgroup\$ – ViTUu Apr 15 '15 at 22:12
  • \$\begingroup\$ I don't think factory methods like this are particularly helpful in Swift. Factory methods are nice in Objective-C when they eliminate [[MyClass alloc] initWith... and turn that into [MyClass myClassWith... but in Swift, I don't think we need nearly as many factory methods. \$\endgroup\$ – nhgrif Apr 15 '15 at 22:17
  • \$\begingroup\$ great observation, i didn't think about it... thanks again \$\endgroup\$ – ViTUu Apr 15 '15 at 22:18
  • \$\begingroup\$ @nhgrif I'm sorry, I am confused as to why this question was off topic based on the comment you left on SO. It appears to have multiple upvotes along with your answer being upvoted and accepted. I want to make sure I don't make incorrect recommendations going forward. \$\endgroup\$ – Joe Apr 16 '15 at 12:49

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.