window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = Fenster if (w.LeadBooster) { console.warn('LeadBooster existiert bereits') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Prinzip offen-geschlossen. Muss ich es jemals anwenden? - The Codest
Der Codest
  • Über uns
  • Dienstleistungen
    • Software-Entwicklung
      • Frontend-Softwareentwicklung
      • Backend-Softwareentwicklung
    • Staff Augmentation
      • Frontend-Entwickler
      • Backend-Entwickler
      • Daten-Ingenieure
      • Cloud-Ingenieure
      • QS-Ingenieure
      • Andere
    • IT-Beratung
      • Prüfung und Beratung
  • Branchen
    • Fintech & Bankwesen
    • E-commerce
    • Adtech
    • Gesundheitstechnik
    • Herstellung
    • Logistik
    • Automobilindustrie
    • IOT
  • Wert für
    • CEO
    • CTO
    • Delivery Manager
  • Unser Team
  • Fallstudien
  • Gewusst wie
    • Blog
    • Begegnungen
    • Webinare
    • Ressourcen
Karriere Kontakt aufnehmen
  • Über uns
  • Dienstleistungen
    • Software-Entwicklung
      • Frontend-Softwareentwicklung
      • Backend-Softwareentwicklung
    • Staff Augmentation
      • Frontend-Entwickler
      • Backend-Entwickler
      • Daten-Ingenieure
      • Cloud-Ingenieure
      • QS-Ingenieure
      • Andere
    • IT-Beratung
      • Prüfung und Beratung
  • Wert für
    • CEO
    • CTO
    • Delivery Manager
  • Unser Team
  • Fallstudien
  • Gewusst wie
    • Blog
    • Begegnungen
    • Webinare
    • Ressourcen
Karriere Kontakt aufnehmen
Pfeil zurück ZURÜCK
2019-07-02
Software-Entwicklung

Prinzip offen-geschlossen. Muss ich es jemals anwenden?

Mateusz Lesniak

Die meisten Entwickler haben schon von dem Prinzip "offen - geschlossen" gehört, einem der SOLID-Prinzipien von Onkel Bob. Es hört sich vernünftig an, kann aber bis zur ersten Anwendung im "Live"-Code ein wenig verschwommen sein. Die vollständige Fassung des Prinzips lautet: Software-Entitäten (Klassen, Module, Funktionen usw.) sollten offen für Erweiterungen, aber geschlossen für Änderungen sein.

Was bedeutet das also wirklich?

Wir sind auf ein Entwicklungsproblem gestoßen, das uns gezeigt hat, was es mit dem Prinzip "offen-geschlossen" wirklich auf sich hat. In einer unserer Webanwendungen hatten wir ein Formular mit zwei Abschnitten (neben anderen):

  • Nachfragekanäle
  • dynamische Filter

Die Benutzer können so viele Filter hinzufügen, wie sie möchten, aber es gibt einige Regeln - die Verfügbarkeit der Filter hängt von den gewählten Kanälen ab.

Kanäle für die Nachfrage: ADAUSTAUSCH, KOPFZEILEBIDDING, RESERVATION, OTHER Dynamische Filter(Dimensionen): Website, Anzeigeeinheit, geo, kreativGröße, Gerät

In diesem Artikel geht es vor allem um Code-Refactor, so wird es eine Menge von Code-Schnipseln unten sein. Ich habe versucht, sie zu reduzieren, aber eine gewisse Menge an Code ist notwendig, um zu zeigen Code-Refactoring. Sie müssen nicht jeden kleinen Teil des Codes verstehen, um die Hauptidee zu verstehen.

Die erste Umsetzung des Problems war einfach:

Klasse ResearchFormStateUpdater {
  update () {
    (...)
    this._updateDynamicFilters();
  }

  _updateDynamicFilters () {
    $('.dynamic-filter').each((_, filter) => {
      $(filter).trigger('dynamicFilter:disableWebsites', this._shouldDisableWebsitesFields());
    });
  }

  _shouldDisableWebsitesFields () {
    return this._shouldDisableFields(ResearchFormStateUpdater.WEBSITE_DISABLING_DEMAND_CHANNELS);
  }

  _shouldDisableFields (disablingDemandChannels) {
    // ist eines von disablingDemandChannels angekreuzt?
  }
}

ResearchFormStateUpdater.WEBSITE_DISABLING_DEMAND_CHANNELS = ['header_bidding', 'reservation', 'other'];

class ResearchDynamicFilter {
  _setDynamicFilterDisableWebsitesEvent () {
    $(this._getBody()).on('dynamicFilter:disableWebsites', (event, shouldDisableWebsites) => {
      // Website-Filter deaktivieren
    });
  }
}

Wie Sie sehen können, sollte der Website-Filter für HEADER nicht verfügbar seinBIDDING, RESERVATION und OTHER Kanäle, so dass sie nur für ADEXCHANGE-Kanal.

Das letzte, was man über Code sagen kann, ist, dass er dauerhaft oder statisch ist. Wir haben also mehr Anfragen von unseren Kunden, die diese Klassen größer und komplexer machen.

Entwicklung von Funktionen

  • Einen weiteren Kanal hinzufügen - EBDA (Der Website-Filter sollte nicht verfügbar sein, solange EBDA gewählt ist):

    • erweitern. DEAKTIVIEREN_ABRUF_KANÄLE nach EBDA-Nachfragekanal
    • viele Namensänderungen - in der ersten Implementierung haben wir die Website in den Namen der Methoden und Konstanten angegeben. Zum Beispiel:

      • isWebsitesDimensionDisabled zu _areFormStateDimensionsDisabled
      • WEBSITE_DEAKTIVIEREN_NACHFRAGE_KANÄLE zu DEAKTIVIEREN_ABRUF_KANÄLE

Spoiler-Alarm -> wenn eine Komponente für Änderungen offen ist, wird es in Zukunft viele Namensänderungen geben. Wir werden dies in den nächsten Schritten nicht beachten.

  • Einen weiteren Filter für 'Produkt' hinzufügen (Produkt Das Schema für die Verfügbarkeit der Filter entspricht dem der Website)

    • ResearchDynamicFilter Klasse muss beim Deaktivieren/Aktivieren von Feldern auf eine weitere Dimension prüfen
  • Gehen wir weiter und fügen wir einen Umschalter über Kanäle -> 'Quelle' hinzu. Alle Nachfragekanäle, die wir bisher hatten, befinden sich in der Quelle Ad Manager. Die neue Quelle - SSP - hat keine Demand Channels und der einzige verfügbare Filter ist Website.

    • Regeln:

      • Es gibt zwei Status der Quelle: Anzeigenmanager und SSP.
      • Alle unsere Nachfragekanäle sind nur für die Ad Manager-Quelle verfügbar.
      • Es gibt keine Nachfragekanäle für SSP-Quellen
      • Website" ist der einzige für die SSP-Quelle verfügbare Filter.
    • Umsetzung:

      • Wenn "SSP" gewählt wird:

        • Deaktivieren Sie Bedarfskanäle.
        • Auslöser dynamicFilter:disableWebsitesAndProducts'. <- beides aktivieren
        • Auslöser dynamicFilter:disableNonSspOptions'
      • Wenn Ad Manager überprüft:

        • Auslöser dynamicFilter:disableWebsitesAndProducts'. <- Wetterkontrolle aktiviert oder deaktiviert
  • Einen weiteren Filter für 'Plattform' hinzufügen

    • Regeln:

      • Die Plattform ist nur verfügbar, wenn die Quelle SSP ist.
    • Schwierigkeitsgrad:

      • Jetzt haben wir "Website", die für den AD_EXCHANGE-Kanal von Ad Manager und für Ssp verfügbar ist, und wir haben "Plattform", die für Ssp, aber nicht für Ad Manager verfügbar ist.
      • Umschalten Der Zustand des Formulars kann sehr kompliziert und verwirrend sein.

Implementierung mit neuer Funktionalität:

Ich präsentiere Ihnen das nächste Snippet hauptsächlich, um die Komplexität des Codes zu zeigen. Sie können ihn gerne ausgeblendet lassen.

Klasse ResearchFormStateUpdater {
  update () {
    (...)
    this._triggerCallbacks();
  }

  _triggerCallbacks () {
    // Auswahl der Rückrufe je nach Quelle
  }

  _adManagerSourceCallbacks () {
    (...)
    this._enableDemandChannels(ResearchFormStateUpdater.AD_MANAGER_DEMAND_CHANNELS);
    this._updateDefaultStateOfDynamicFilters();
    this._updateAdManagerDynamicFilters();
  }

  _sspSourceCallbacks () {
    (...)
    this._removeDemandChannelsActiveClassAndDisable(ResearchFormStateUpdater.AD_MANAGER_DEMAND_CHANNELS);
    this._updateDefaultStateOfDynamicFilters();
  }

  _updateDefaultStateOfDynamicFilters () {
    $('.dynamic-filter').each((_, filter) => {
      $(filter).trigger('dynamicFilter:enableSspFilters', this.isSourceSsp);
    });
  }

  _updateAdManagerDynamicFilters () {
    $('.dynamic-filter').each((_, filter) => {
      $(filter).trigger('dynamicFilter:disableWebsitesAndProducts', this._areFormStateDimensionsDisabled() && !this.isSourceSsp);
    });
  }

  _shouldDisableFields (disablingDemandChannels) {
    // ist eines von disablingDemandChannels geprüft
  }
}

ResearchFormStateUpdater.AD_MANAGER_DISABLING_DEMAND_CHANNELS = ['header_bidding', 'reservation', 'other', 'ebda'];

class ResearchDynamicFilter {
  // Ich habe diese beiden Methoden nicht vereinfacht, um die aktuelle Komplexität der Implementierung zu zeigen

  _setDefaultDynamicFiltersToggleEvent () {
    $(this._getBody()).on('dynamicFilter:enableSspFilters', (event, shouldEnableSspOptions) => {
      this._setDefaultFiltersOptionDisabledState(shouldEnableSspOptions);

      const selectedFilterDimension = this._getFiltersDimension().find('option:selected').val();
      if (selectedFilterDimension === 'Website') {
        this._toggleChosenFilterDisabledState(false);
      } else if (selectedFilterDimension === 'Plattform') {
        this._toggleChosenFilterDisabledState(!shouldEnableSspOptions);
      } else {
        this._toggleChosenFilterDisabledState(shouldEnableSspOptions);
      }
    });
  }

  _setDynamicFilterDisableWebsitesAndProductsEvent () {
    $(this._getBody()).on('dynamicFilter:disableWebsitesAndProducts', (event, shouldDisableWebsitesAndProducts) => {
      const selectedFilterDimension = this._getFiltersDimension().find('option:selected').val();
      if ($.inArray(selectedFilterDimension, ['website', 'product']) >= 0) {
        this._toggleChosenFilterDisabledState(shouldDisableWebsitesAndProducts);
      }
      this._setMethodSelectWebsiteAndProductOptionDisabledState(shouldDisableWebsitesAndProducts);
    });
  }

  _toggleNonSspFilters (dimensionSelect, shouldDisable) {
    $.each(ResearchDynamicFilter.NON_SSP_FILTERS_OPTIONS, (_, option) => {
      // Umschalten des Filterstatus in Abhängigkeit von 'shouldDisable'
    });
  }
}

ResearchDynamicFilter.NON_SSP_FILTERS_OPTIONS = ['ad_unit', 'creative_size', 'geo', 'device', 'product'];

Wir verwenden immer noch einige 'Umschalten' Mechanismus. Es ist wirklich schwer, 4 Hebel umzulegen und den erwarteten Zustand zu erreichen, und jetzt muss DynamicFilter wissen, welche Dimensionen nicht für die SPS-Quelle geeignet sind.

Wir haben ResearchFormStateUpdater, warum sollte er nicht dafür zuständig sein?

Letzter Antrag

Einen weiteren Filter hinzufügen für 'Yield partner'.

Das war genau der Moment, in dem wir beschlossen, diese Klassen zu überarbeiten. Die analysierten Kanäle und Filter sind nur ein kleiner Teil des Problems. Es gibt hier mehrere Formularabschnitte und alle haben das gleiche Problem. Unser Refactor sollte die Notwendigkeit neutralisieren, Methoden innerhalb dieser Klassen zu ändern, *um* neue Kanäle oder Dimensionen hinzuzufügen.

Im nächsten Schnipsel habe ich die Hauptklassen fast so belassen, wie sie in unserem Produktionscode sind, um Ihnen zu zeigen, wie einfach sie jetzt zu verstehen sind.

Klasse ResearchFormStateUpdater {
  update () {
    (...)
    this._updateDynamicFilters();
  }

  _updateDynamicFilters () {
    this._toggleAllDynamicFiltersState(this._dynamicFiltersDimensionsToBeDisabled());
  }

  _dynamicFiltersDimensionsToBeDisabled () {
    if (this.isSourceSsp) { return ResearchFormStateUpdater.NO_SSP_FILTERS; }

    var disabledFilters = ResearchFormStateUpdater.ONLY_SSP_FILTERS;
    if (this.areDemandChannelsExceptAdxSelected) {
      disabledFilters = disabledFilters.concat(ResearchFormStateUpdater.ONLY_ADX_FILTERS);
    }
    return disabledFilters;
  }

  _toggleAllDynamicFiltersState (disabledFilters) {
    $('.dynamic-filter').each((_, filter) => {
      this._toggleDynamicFilterState(filter, disabledFilters);
    });
  }

  _toggleDynamicFilterState (dynamicFilter, disabledFilters) {
    $(dynamicFilter).trigger('dynamicFilter:toggleDynamicFilters', disabledFilters);
  }
}

ResearchFormStateUpdater.NO_SSP_FILTERS = ['ad_unit', 'creative_size', 'geo', 'device', 'product'];

ResearchFormStateUpdater.ONLY_SSP_FILTERS = ['Plattform'];

ResearchFormStateUpdater.ONLY_ADX_FILTERS = ['website', 'product'];

class ResearchDynamicFilter {
  _setDynamicFiltersToggleEvent () {
    $(this._getBody()).on('dynamicFilter:toggleDynamicFilters', (event, disabledFilters) => {
      this._disableFilters(disabledFilters.split(','));
      this._enableFilters(disabledFilters.split(',')));
    });
  }

  _disableFilters (filtersToDisable) {
    // filterToDisable deaktivieren
  }

  _enableFilters (filtersToDisable) {
    const filtersToEnable = $(ResearchDynamicFilter.ALL_FILTERS).not(filtersToDisable).get();
    // enable filtersToEnable
  }
}

ResearchDynamicFilter.ALL_FILTERS = ['website', 'ad_unit', 'creative_size', 'geo', 'device', 'product', 'platform'];

Wir haben es geschafft! Haben wir?

Das Einzige, was "ResearchDynamicFilter" jetzt wissen muss, ist eine Liste aller Filter - das scheint fair. Der Rest der Logik und Steuerung kommt von oben - einige höhere Methoden und Konstanten.

Probieren wir also unsere neue Struktur aus, indem wir einen Filter für "Yield_partner" hinzufügen:

class ResearchFormStateUpdater {
  _dynamicFiltersDimensionsToBeDisabled () {
    (...)
    if (this.areDemandChannelsExceptEbdaSelected) {
      disabledFilters = disabledFilters.concat(ResearchFormStateUpdater.ONLY_EBDA_FILTERS);
    }
    return disabledFilters;
  }
}

ResearchFormStateUpdater.NO_SSP_FILTERS = [(...), 'yield_partner'];

ResearchFormStateUpdater.ONLY_EBDA_FILTERS = [(...), 'yield_partner'];

ResearchDynamicFilter.ALL_FILTERS = [(...), 'yield_partner']; ResearchDynamicFilter.ALL_FILTERS = [(...), 'yield_partner'];

Wie Sie sehen, geht es nur darum, einige Werte zu Konstanten und einige zusätzliche Bedingungen hinzuzufügen.

Dank des Prinzips "offen-geschlossen" können wir die Geschäftslogik des Formulars ändern, indem wir lediglich einige Werte und Bedingungen auf einer höheren Abstraktionsebene hinzufügen. Wir müssen nicht ins Innere der Komponente gehen und irgendetwas ändern. Diese Umstrukturierung betraf das gesamte Formular und es gab weitere Abschnitte, die jetzt alle dem Prinzip der offenen und geschlossenen Struktur folgen.

Wir haben den Umfang des Codes nicht verringert, sondern ihn sogar erhöht (vorher/nachher):

  • ResearchFormStateUpdater - 211/282 Zeilen
  • ResearchDynamicFilter - 267/256 Zeilen

Alles dreht sich um die Sammlung in Konstanten -> das ist jetzt unsere öffentliche Schnittstelle, unsere Konsole zur Steuerung von Prozessen ohne Dutzende von Schaltern.

Lesen Sie auch:

  • Wie schreibt man einen guten und hochwertigen Code?
  • Vuelendar. Ein neues Projekt von Codest auf der Grundlage von Vue.js
  • Was ist Ruby on Jets und wie kann man damit eine Anwendung erstellen?

Ähnliche Artikel

Software-Entwicklung

Zukunftssichere Web-Apps bauen: Einblicke vom The Codest-Expertenteam

Entdecken Sie, wie sich The Codest bei der Erstellung skalierbarer, interaktiver Webanwendungen mit Spitzentechnologien auszeichnet, die nahtlose Benutzererfahrungen auf allen Plattformen bieten. Erfahren Sie, wie unsere Expertise die digitale Transformation und...

DAS SCHÖNSTE
Software-Entwicklung

Top 10 Softwareentwicklungsunternehmen in Lettland

Erfahren Sie in unserem neuesten Artikel mehr über die besten Softwareentwicklungsunternehmen Lettlands und ihre innovativen Lösungen. Entdecken Sie, wie diese Technologieführer Ihr Unternehmen voranbringen können.

thecodest
Enterprise & Scaleups Lösungen

Grundlagen der Java-Softwareentwicklung: Ein Leitfaden für erfolgreiches Outsourcing

Entdecken Sie diesen wichtigen Leitfaden zum erfolgreichen Outsourcing der Java-Softwareentwicklung, um die Effizienz zu steigern, auf Fachwissen zuzugreifen und den Projekterfolg mit The Codest voranzutreiben.

thecodest
Software-Entwicklung

Der ultimative Leitfaden für Outsourcing in Polen

Der Anstieg des Outsourcings in Polen wird durch wirtschaftliche, bildungspolitische und technologische Fortschritte angetrieben, die das IT-Wachstum und ein unternehmensfreundliches Klima fördern.

TheCodest
Enterprise & Scaleups Lösungen

Der vollständige Leitfaden für IT-Audit-Tools und -Techniken

IT-Audits gewährleisten sichere, effiziente und gesetzeskonforme Systeme. Erfahren Sie mehr über ihre Bedeutung, indem Sie den vollständigen Artikel lesen.

Der Codest
Jakub Jakubowicz CTO & Mitbegründer

Abonnieren Sie unsere Wissensdatenbank und bleiben Sie auf dem Laufenden über das Fachwissen aus dem IT-Sektor.

    Über uns

    The Codest - Internationales Software-Unternehmen mit technischen Zentren in Polen.

    Vereinigtes Königreich - Hauptsitz

    • Büro 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale Tech-Hubs

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polen

      Der Codest

    • Startseite
    • Über uns
    • Dienstleistungen
    • Fallstudien
    • Gewusst wie
    • Karriere
    • Wörterbuch

      Dienstleistungen

    • IT-Beratung
    • Software-Entwicklung
    • Backend-Softwareentwicklung
    • Frontend-Softwareentwicklung
    • Staff Augmentation
    • Backend-Entwickler
    • Cloud-Ingenieure
    • Daten-Ingenieure
    • Andere
    • QS-Ingenieure

      Ressourcen

    • Fakten und Mythen über die Zusammenarbeit mit einem externen Softwareentwicklungspartner
    • Aus den USA nach Europa: Warum entscheiden sich amerikanische Start-ups für eine Verlagerung nach Europa?
    • Tech Offshore Development Hubs im Vergleich: Tech Offshore Europa (Polen), ASEAN (Philippinen), Eurasien (Türkei)
    • Was sind die größten Herausforderungen für CTOs und CIOs?
    • Der Codest
    • Der Codest
    • Der Codest
    • Privacy policy
    • Website terms of use

    Urheberrecht © 2025 von The Codest. Alle Rechte vorbehalten.

    de_DEGerman
    en_USEnglish sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek de_DEGerman