¿Qué patrón de diseño del complemento jQuery debo usar?

Necesito crear un complemento jQuery que devuelva una sola instancia por ID de selector. El complemento debe y solo se usará en elementos con id (no es posible usar un selector que coincida con muchos elementos), por lo que se debe usar así:

$('#element-id').myPlugin(options);
Necesito poder tener pocos métodos privados para el complemento, así como pocos métodos públicos. Puedo lograrlo, pero mi problema principal es que quiero obtener la misma instancia cada vez que llamo $ ('# element-id'). MyPlugin ().Y quiero tener un código que debería ejecutarse solo la primera vez que se inicializa el complemento para una ID (construcción) determinada.Losoptionsl parámetro @ debe proporcionarse la primera vez, para la construcción, después de eso no quiero que se ejecute la construcción, de modo que pueda acceder al complemento como $ ('# element-id'). myPlugin ()El complemento debería poder trabajar con múltiples elementos (generalmente hasta 2) en la misma página (pero todos y cada uno de ellos necesitarán su propia configuración, nuevamente; se inicializarán por ID, no por ejemplo, un selector de clase común) .La sintaxis anterior es solo, por ejemplo, estoy abierto a cualquier sugerencia sobre cómo lograr ese patrón

Tengo bastante experiencia en OOP con otro lenguaje, pero tengo un conocimiento limitado de JavaScript y estoy realmente confundido sobre cómo hacerlo correctamente.

EDITA

Para elaborar: este complemento es un contenedor de API de GoogleMaps v3 (ayudante) para ayudarme a deshacerme de la duplicación de código, ya que uso mapas de Google en muchos lugares, generalmente con marcadores. Esta es la biblioteca actual (se eliminó un montón de código, solo quedan los métodos más importantes para ver):

;(function($) {
    /**
     * csGoogleMapsHelper set function.
     * @param options map settings for the google maps helper. Available options are as follows:
     * - mapTypeId: constant, http://code.google.com/apis/maps/documentation/javascript/reference.html#MapTypeId
     * - mapTypeControlPosition: constant, http://code.google.com/apis/maps/documentation/javascript/reference.html#ControlPosition
     * - mapTypeControlStyle: constant, http://code.google.com/apis/maps/documentation/javascript/reference.html#MapTypeControlStyle
     * - mapCenterLatitude: decimal, -180 to +180 latitude of the map initial center
     * - mapCenterLongitude: decimal, -90 to +90 latitude of the map initial center
     * - mapDefaultZoomLevel: integer, map zoom level
     * 
     * - clusterEnabled: bool
     * - clusterMaxZoom: integer, beyond this zoom level there will be no clustering
     */
    $.fn.csGoogleMapsHelper = function(options) {
        var id = $(this).attr('id');
        var settings = $.extend(true, $.fn.csGoogleMapsHelper.defaults, options);

        $.fn.csGoogleMapsHelper.settings[id] = settings;

        var mapOptions = {
            mapTypeId: settings.mapTypeId,
            center: new google.maps.LatLng(settings.mapCenterLatitude, settings.mapCenterLongitude),
            zoom: settings.mapDefaultZoomLevel,
            mapTypeControlOptions: {
                position: settings.mapTypeControlPosition,
                style: settings.mapTypeControlStyle
            }
        };

        $.fn.csGoogleMapsHelper.map[id] = new google.maps.Map(document.getElementById(id), mapOptions);
    };

    /**
     * 
     * 
     * @param options settings object for the marker, available settings:
     * 
     * - VenueID: int
     * - VenueLatitude: decimal
     * - VenueLongitude: decimal
     * - VenueMapIconImg: optional, url to icon img
     * - VenueMapIconWidth: int, icon img width in pixels
     * - VenueMapIconHeight: int, icon img height in pixels
     * 
     * - title: string, marker title
     * - draggable: bool
     * 
     */
    $.fn.csGoogleMapsHelper.createMarker = function(id, options, pushToMarkersArray) {
        var settings = $.fn.csGoogleMapsHelper.settings[id];

        markerOptions = {
                map:  $.fn.csGoogleMapsHelper.map[id],
                position: options.position || new google.maps.LatLng(options.VenueLatitude, options.VenueLongitude),
                title: options.title,
                VenueID: options.VenueID,
                draggable: options.draggable
        };

        if (options.VenueMapIconImg)
            markerOptions.icon = new google.maps.MarkerImage(options.VenueMapIconImg, new google.maps.Size(options.VenueMapIconWidth, options.VenueMapIconHeight));

        var marker = new google.maps.Marker(markerOptions);
        // lets have the VenueID as marker property
        if (!marker.VenueID)
            marker.VenueID = null;

        google.maps.event.addListener(marker, 'click', function() {
             $.fn.csGoogleMapsHelper.loadMarkerInfoWindowContent(id, this);
        });

        if (pushToMarkersArray) {
            // let's collect the markers as array in order to be loop them and set event handlers and other common stuff
             $.fn.csGoogleMapsHelper.markers.push(marker);
        }

        return marker;
    };

    // this loads the marker info window content with ajax
    $.fn.csGoogleMapsHelper.loadMarkerInfoWindowContent = function(id, marker) {
        var settings = $.fn.csGoogleMapsHelper.settings[id];
        var infoWindowContent = null;

        if (!marker.infoWindow) {
            $.ajax({
                async: false, 
                type: 'GET', 
                url: settings.mapMarkersInfoWindowAjaxUrl, 
                data: { 'VenueID': marker.VenueID },
                success: function(data) {
                    var infoWindowContent = data;
                    infoWindowOptions = { content: infoWindowContent };
                    marker.infoWindow = new google.maps.InfoWindow(infoWindowOptions);
                }
            });
        }

        // close the existing opened info window on the map (if such)
        if ($.fn.csGoogleMapsHelper.infoWindow)
            $.fn.csGoogleMapsHelper.infoWindow.close();

        if (marker.infoWindow) {
            $.fn.csGoogleMapsHelper.infoWindow = marker.infoWindow;
            marker.infoWindow.open(marker.map, marker);
        }
    };

    $.fn.csGoogleMapsHelper.finalize = function(id) {
        var settings = $.fn.csGoogleMapsHelper.settings[id];
        if (settings.clusterEnabled) {
            var clusterOptions = {
                cluster: true,
                maxZoom: settings.clusterMaxZoom
            };

            $.fn.csGoogleMapsHelper.showClustered(id, clusterOptions);

            var venue = $.fn.csGoogleMapsHelper.findMarkerByVenueId(settings.selectedVenueId);
            if (venue) {
                google.maps.event.trigger(venue, 'click');
            }
        }

        $.fn.csGoogleMapsHelper.setVenueEvents(id);
    };

    // set the common click event to all the venues
    $.fn.csGoogleMapsHelper.setVenueEvents = function(id) {
        for (var i in $.fn.csGoogleMapsHelper.markers) {
            google.maps.event.addListener($.fn.csGoogleMapsHelper.markers[i], 'click', function(event){
                $.fn.csGoogleMapsHelper.setVenueInput(id, this);
            });
        }
    };

    // show the clustering (grouping of markers)
    $.fn.csGoogleMapsHelper.showClustered = function(id, options) {
        // show clustered
        var clustered = new MarkerClusterer($.fn.csGoogleMapsHelper.map[id], $.fn.csGoogleMapsHelper.markers, options);
        return clustered;
    };

    $.fn.csGoogleMapsHelper.settings = {};
    $.fn.csGoogleMapsHelper.map = {};
    $.fn.csGoogleMapsHelper.infoWindow = null;
    $.fn.csGoogleMapsHelper.markers = [];
})(jQuery);

Su uso se ve así (en realidad no es exactamente así, porque hay un contenedor PHP para automatizarlo con una sola llamada, pero básicamente):

$js = "$('#$id').csGoogleMapsHelper($jsOptions);\n";

if ($this->venues !== null) {
    foreach ($this->venues as $row) {
        $data = GoogleMapsHelper::getVenueMarkerOptionsJs($row);
        $js .= "$.fn.csGoogleMapsHelper.createMarker('$id', $data, true);\n";
    }
}

$js .= "$.fn.csGoogleMapsHelper.finalize('$id');\n";
echo $js;

Los problemas de la implementación anterior son que no me gusta mantener un mapa hash para "configuraciones" y "mapas"

Los$id es el ID del elemento DIV donde se inicializa el mapa. Se utiliza como clave en .map y .settings tiene mapas donde guardo la configuración y la instancia de GoogleMaps MapObject para cada uno de estos GoogleMaps inicializados en la página. Los$jsOptions y$data del código PHP son objetos JSON.

Ahora necesito poder crear una instancia de GoogleMapsHelper que contenga su propia configuración y un objeto de mapa de GoogleMaps para que después de inicializarlo en cierto elemento (por su ID), pueda reutilizar esa instancia. Pero si lo inicializo en N elementos en la página, todos y cada uno de ellos deberían tener su propia configuración, objeto de mapa, etc.

No insisto en que esto se implemente como un complemento jQuery! Insisto en que es flexible y ampliable, porque lo usaré en un proyecto grande con más de una docena de pantallas diferentes actualmente planificadas donde se usará, por lo que en unos meses, cambiar su interfaz de uso sería una pesadilla para refactorizar todo el proyecto. .

Agregaré una recompensa por esto.

Respuestas a la pregunta(7)

Su respuesta a la pregunta