Is inheritance the right way to solve this problem?

I am new to f #. I want to bring the list of search results to the fore. However, there may be several types of search results (e.g. BlogResult, MovieResultetc.), each with its own properties (for example MovieResult.PosterIcon). The user interface will know these types and will display each type accordingly. The main search API will not be aware of these types and only provides the infrastructure that the "provider" must implement, including the type that it will return. For instance,BlogProviderperform the necessary functions and the corresponding type of search result. The application will register all of these suppliers together in the main structure so that all results should be returned in a ranked manner as a single list of items. It is highly likely that these providers will exist in their own assembly, separate from the application and the main search API.

My OO brain wants to have a class or interface SearchResultfrom which all other types of results are inherited. Is there a more functional way to handle this?

Update The application is an ASP.NET MVC application. Each result is presented in partial presentation. The site itself does not need to change when a new type of search result is added. There is only a new partial view. This does not violate the Open / Closed principle. Technically, I could suggest the provider to create a template for partial viewing. However, the ceremony code is not worth the effort.

+4
source share
2 answers

It may be my limited imagination and poor design skills, but whenever I was presented with such requirements as above, I was forced to make some kind of compromise. This is why it is also difficult in OOP:

.

. , :

  • "" . OOD, , ( ) . ad-hoc , Visitor, / , "" .
  • "" . ( ) ( ) , . Render, :
    • : void Render(Canvas) () - - canvas, .
    • - , HTML: string Render() ( , ).

, .

F #, .

, "" , :

open System

type BlogResult = {
    Title : string
    Summary : string }

type MovieResult = {
    Title : string
    PosterIcon : Uri }

type SearchResult =
    | BlogResult of BlogResult
    | MovieResult of MovieResult

, OOD : () , .

, Unions F #, ( Visitor).

. , , .

, , , string Render(), : unit -> string.

"", , . .

+2

: F #. - F #. , , # .

"", . , Scala Haskell, , typeclasses, , .

, ? , F # A) , B) . .

:

// Blog.fs
type Blog {...}
[<SomeProviderAttribute>]let getBlogs() = ... // returns Blog seq

// Movie.fs
type Movie = {...}
[<SomeProviderAttribute>]let getMovies() = ... // returns Movie seq

: ( )

// UiBase.fs
class Renderable where render :: 'T -> string

// BlogUi.fs
instance Renderable Blog where render blog = blog.header + blog.text

// MovieUi.fs
instance Renderable Movie where render movie = movie.title + movie.description

, . , , :

// MainUi.fs
open Blog; open Movie; open UiBase; open BlogUi; open MovieUi
// Just like you'd have to call "using" in C# to get the extention methods,
// you have to open these to get the type classes

let dataProviders = ... // Some assembly search and reflection here; 
                    // say it returns [getBlogs; getMovies]
                    // (and note without the common typeclass,
                    //    those two would be incompatible)

let renderedStrings = 
  seq { for provider in dataProviders do
          for renderable in provider() do
            yield render renderable }

, ( ) Blog Movie , "" . , .

... , F # .

+2

Source: https://habr.com/ru/post/1533651/


All Articles