Dziedziczenie vs Kompozycja

0

Czy dobrze zrozumiałem temat?

Poniżej przedstawie 2 kody robiące to samo, z których jeden jest wg mnie zbudowany na dziedziczeniu a drugi na kompozycji. Który lepszy?

KOD 1:

/**
 * 
 * The topic of the forum. For navigating through pages of the topic and getting
 * them.
 *
 */
public abstract class Topic implements Iterable<Page> {

	protected String urlBase;
	protected String pagePattern;

	public Topic(String urlBase, String patternForPageNumber) {
		this.pagePattern = patternForPageNumber;
		this.urlBase = urlBase.replaceAll(Pattern.quote(patternForPageNumber) + "\\d+", "");
	}

	public Topic(String url) {
		this.pagePattern = "?page=";
		this.urlBase = url.replaceAll(Pattern.quote(pagePattern) + "\\d+", "");
	}

	public abstract int getMaxPageNumber();

	public abstract Page getPage(int pageNumber);

        public Iterator<Page> iterator();

}
/**
 * 
 * The Topic: anonimowiinformatycy.pl
 *
 */
public class TopicAnonimowiInformatycy extends Topic {

	public TopicAnonimowiInformatycy(String url, String patternForPageNumber) {
		super(url, patternForPageNumber);
	}

	public TopicAnonimowiInformatycy(String url) {
		super(url);
	}

	@Override
	public int getMaxPageNumber() {
            // ...
            // complex implementation here
            // ...
	}

        @Override
	public Page getPage(int pageNumber) {
            // ...
            // complex implementation here
            // ...
	}

	@Override
	public Iterator<Page> iterator() {
		return this.new IteratorAnonimowiInformatycy();
	}

	private class IteratorAnonimowiInformatycy implements Iterator<Page> {

		private int count = 1;

		@Override
		public boolean hasNext() {
			return (count <= AnonimowiInformatycy.this.getMaxPageNumber());
		}

		@Override
		public Page next() {
			return TopicAnonimowiInformatycy.this.getPage(count++);
		}

	}

}
/**
 * 
 * The Topic: 4programmers.net
 *
 */
public class Topic4programmers extends Topic {

	public Topic4programmers(String url, String patternForPageNumber) {
		super(url, patternForPageNumber);
	}

	public Topic4programmers(String url) {
		super(url);
	}

	@Override
	public int getMaxPageNumber() {
            // ...
            // complex implementation here
            // ...
	}

        @Override
	public Page getPage(int pageNumber) {
            // ...
            // complex implementation here
            // ...
	}

	@Override
	public Iterator<Page> iterator() {
		return this.new Iterator4programmers();
	}

	private class Iterator4programmers implements Iterator<Page> {

		private int count = 1;

		@Override
		public boolean hasNext() {
			return (count <= Topic4programmers.this.getMaxPageNumber());
		}

		@Override
		public Page next() {
			return Topic4programmers.this.getPage(count++);
		}

	}

}

KOD 2:

public class Topic implements IMaxPageNumber, IPageGetter{
	
	private String urlBase;
	private String pagePattern;
	IMaxPageNumber iMaxPageNumber;
	IPageGetter iPageGetter;
	

	public Topic(String urlBase, String patternForPageNumber) {
		this.pagePattern = patternForPageNumber;
		this.urlBase = urlBase.replaceAll(Pattern.quote(patternForPageNumber) + "\\d+", "");
	}

	public Topic(String url) {
		this.pagePattern = "?page=";
		this.urlBase = url.replaceAll(Pattern.quote(pagePattern) + "\\d+", "");
	}
	
	public int getMaxPageNumber() {
		iMaxPageNumber.getMaxPageNumber();
	}

	public Page getPage(int pageNumber) {
		iPageGetter.getPage(pageNumber);
	}
	
	public setIMaxPageNumber void(IMaxPageNumber iMaxPageNumber) {
		this.iMaxPageNumber = iMaxPageNumber;
	}
	
	public setIMaxPageNumber void(IMaxPageNumber iMaxPageNumber) {
		this.iMaxPageNumber = iMaxPageNumber;
	}
	
	public Iterator<Page> iterator() {
		return this.new IteratorTopic();
	}

	private class IteratorTopic implements Iterator<Page> {

		private int count = 1;

		@Override
		public boolean hasNext() {
			return (count <= Topic.this.getMaxPageNumber());
		}

		@Override
		public Page next() {
			return Topic.this.getPage(count++);
		}

	}
}
public interface IMaxPageNumber {
	public int getMaxPageNumber();
}
public interface IPageGetter {
	public int getPage(int pageNumber);
}
public MaxPageNumberImpl4programmers {
    // ...
    // complex implementation here
    // ...
}
public PageGetterImpl4programmers{
    // ...
    // complex implementation here
    // ...
}
public MaxPageNumberImplAnonimowiInformatycy {
    // ...
    // complex implementation here
    // ...
}
public PageGetterImplAnonimowiInformatycy{
    // ...
    // complex implementation here
    // ...
}

W przypadku 1 jak będę chciał liczbę postów tematu z 4programmers to napiszę:

Topic topic = new Topic4programmers(url, pattern);
topic.getMaxPageNumber();

a w 2 przypadku:

Topic topic = new Topic(url, pattern);
topic.setIMaxPageNumber(new MaxPageNumberImpl4programmers );
topic.getMaxPageNumber();

sory za nazwy interfejsów.

0

Po co w KODzie 2 zawierasz składniki będące interfejsami, które i tak implementujesz?

1

Jak dla mnie, to oba kody są oparte na dziedziczeniu, z czego ten drugi

to jakieś... nieporozumienie.

Kompozycja polega na tym, że masz np.

class File {
    public InputStream getInputStream() {...}
    public OutputStream getOutputStream() {...};
}

Taki kod oparty jedynie na dziedziczeniu wyglądałby tak:

class FileStream implements InputStream, OutputStream {...}

Ogólnie kompozycja nie wyklucza dziedziczenia (patrz Dependency Injection), te techniki powinny naturalnie się przenikać.

  1. Kiedy masz klasę Samochód, to nie implementujesz w niej interfejsów Koło, Silnik itd., tylko robisz metody getKoło() i getSilnik() - to jest kompozycja.
  2. Kiedy robisz klasę, po której instancjach można iterować, to nie robisz metody getIterable(), tylko implementujesz interfejs Iterable - to jest dziedziczenie.

Zauważ, że w przypadku 1 zarówno Koło jak i Silnik są gdzieś implementowane, więc w tym wypadku dziedziczenie jest naturalnym wymogiem kompozycji.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.