Value based dispatch with a string presents some challenges.
If you use a Symbol, an interned string, directly, then value based dispatch can be made very efficient due to constant propagation.
julia> @btime ValueFruitFactory.fruit(:orange)
1.424 ns (0 allocations: 0 bytes)
Main.ValueFruitFactory.Orange()
julia> f() = ValueFruitFactory.fruit(:orange)
f (generic function with 1 method)
julia> @btime f()
1.423 ns (0 allocations: 0 bytes)
Main.ValueFruitFactory.Orange()
julia> @code_typed f()
CodeInfo(
1 ─ return $(QuoteNode(Main.ValueFruitFactory.Orange()))
) => Main.ValueFruitFactory.Orange
Compare the typed code with the string version.
julia> @code_typed g()
CodeInfo(
1 ─ %1 = $(Expr(:foreigncall, :(:jl_string_ptr), Ptr{UInt8}, svec(Any), 0, :(:ccall), "orange"))::Ptr{UInt8}
│ %2 = Core.sizeof("orange")::Int64
│ %3 = $(Expr(:foreigncall, :(:jl_symbol_n), Ref{Symbol}, svec(Ptr{UInt8}, Int64), 0, :(:ccall), :(%1), :(%2), "orange"))::Symbol
│ %4 = invoke Main.ValueFruitFactory.fruit(%3::Symbol)::Union{Main.ValueFruitFactory.Apple, Main.ValueFruitFactory.Orange}
└── return %4
) => Union{Main.ValueFruitFactory.Apple, Main.ValueFruitFactory.Orange}