Który kod lepszy?

0

Który kod lepszy?

def main() {
    writer = getWriterInstance()
    writeHeader(writer)
    writeBody(writer)
    writeFooter(writer)
    writer.close()
}

def writeHeader(writer) {
    str = "xxxxxxxxxxx"
    writer.write(str)
}
def writeBody(writer) {
    str = "yyyyyyyyyyyy"
    writer.write(str)
}
def writeFooter(writer) {
    str = "zzzzzzzzzzzzzzz"
    writer.write(str)
}

czy

def main() {
    writer = getWriterInstance()
    writer.write(getHeader())
    writer.write(getBody())    
    writer.write(getFooter())
    writer.close()
}

def getHeader() {
    return "xxxxxxxxxxx"
}
def getBody() {
    return "yyyyyyyyyy"
}
def getFooter() {
    return "zzzzzzzzzzzzzz"
}
4

2

brak zależności do jakiegoś writera, który i tak nic nie robi

1

To mi nie wygląda jak Python ;-)

0

kolejne pytanie:

Lepiej tak:

def main() {
    writer = getWriterInstance()
    writer.write(getHeader())
    writer.write(getBody())    
    writer.write(getFooter())
    writer.close()
}

def getHeader() {
    return """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """
}
def getBody() {
    return """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """
}
def getFooter() {
    return """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """
}

czy tak:

def main() {
    writer = getWriterInstance()
    stringsss = new Stringsss()
    writer.write(stringsss.header)
    writer.write(stringsss.body)    
    writer.write(stringsss.footer)
    stringsss = null
    gc()
    writer.close()
}
class Stringsss {
   header = """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """

    body= """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """

    footer= """
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
      | xxxxxxxxxxx
    """
}
0

Pierwszy jest kiepski, bo miesza pobieranie danych z konkretnym sposobem ich użycia.

Drugi jest lepszy, bo funkcje po prostu zwracają dane, które możesz sobie użyć jakkolwiek.

 writer.write(getHeader())
 writer.write(getBody())    
 writer.write(getFooter())

Nie musisz powtarzać cały czas write.write:

 for getData in [getHeader, getBody, getFooter]:  
    writer.write(getData())

A poza tym nie jest to Python (to, co w pierwszym poście), bo w Pythonie nie ma klamerek.

1

słabe te przyklady

0

Pisanie getterów/setterów w językach dynamicznych, takich jak Python, zazwyczaj mija się z celem. Co chcesz osiągnąć, korzystając z nich? Bo enkapsulacja, na przykład, odpada — w Pythonie nic nie jest prywatne.

0
Althorion napisał(a):

Pisanie getterów/setterów w językach dynamicznych, takich jak Python, zazwyczaj mija się z celem. Co chcesz osiągnąć, korzystając z nich? Bo enkapsulacja, na przykład, odpada — w Pythonie nic nie jest prywatne.

single reponsibility?

0

I w jaki sposób ta zasada jest lepiej realizowana przez cośtam.getBody() niż cośtam.body? Czy cośtam.setBody(123) niż cośtam.body = 123?

1
Althorion napisał(a):

I w jaki sposób ta zasada jest lepiej realizowana przez cośtam.getBody() niż cośtam.body? Czy cośtam.setBody(123) niż cośtam.body = 123?

ale nie o to mi chodzi :(

0

OK, to do czego używasz getterów/setterów, skoro nie do tego? Ja nie mówię, że to nigdy nie ma sensu — może akurat u Ciebie ma — tylko że jest podejrzane, bo typowy zysk z tego typu metod w Pythonie znika.

0

Jak ten kod powinien wyglądać moim zdaniem [pseudo kod]:

def main() {
    writer = getWriterInstance()
    writer.write("""
      | header
      | body
      | footer
    """)
    writer.close()
}

Jak mógłby wyglądać gdybym znał kontekst [pseudo kod]:

WriterInterface
write(writer)

HeaderWriter implements WriterInterface
write(writer) -> writer.write('header')

BodyWriter implements WriterInterface
write(writer) -> writer.write('body')

FooterWriter implements WriterInterface
write(writer) -> writer.write('footer')

WriterGroup implements WriterInterface
constructor(writers: WriterInterface[]) -> this.writers = writers
write(writer) -> writers.forEach(singleWriter -> singleWriter.write(writer))

def main() {
    writer = getWriterInstance()
    myDomainWriter = new WriterGroup([new HeaderWriter(), new BodyWriter(), new FooterWriter()])
    myDomainWriter.write(writer)
    writer.close()
}

Co zyskujesz pisząc w ten sposób? Ten myDomainWriter możesz sobie stworzyć w formie DI w jakimś configu i operować na nim wszędzie (bez tego musiałbyś w każdym miejscu robić te swoje getHeader, getFooter itp.). Jak chcesz dodać nowy writer to piszesz osobną klasę (czyli kod każdego writera ma swoje określone miejsce i nie wychodzi poza to miejsce, co nie ma nic wspólnego z single responsibility principle), tylko w 1 miejscu rozszerzasz swój myDomainWriter, dodatkowo dzięki temu, że implementuje on ten sam interface (dzięki Composite Design Pattern) możesz dowolnie zagnieżdzać swoje writery np. HeaderWriter możesz zmienić na WriterGroup i w nim umieścić kilka Writerów.

Dodatkowo wyżej mam złe nazewnictwo, bo można wyróżnić 2 rodzaje writerów (1 jest techniczny/infrastructure) i to jest to getWriterInstance, drugi jest domenowy WriterInterface - ale samo słowo Writer tak mało mówi, że nie wiem o co Ci chodziło. W IT wszystko co rzuca na output to może być Writer, ale rzadko kiedy jest to faktycznie Writer, to może być np. PostWriter, HeaderWriter ale też HTMLWriter, XMLWriter itd.

Poczytaj o Composite Design Pattern
https://sourcemaking.com/design_patterns/composite

1

@Markuz:

w nazwie tematu nie ma anti pattern albo overengineering albo enterprise™ :D

0

Context manager?

with Writer() as f:
    f.write(...)

1 użytkowników online, w tym zalogowanych: 0, gości: 1