LINUX.ORG.RU

Ответ на: комментарий от Karapuz

Это уже даже не устрица, а такой панцирный ктулху.

wfrr ★★☆
()
Ответ на: комментарий от no-dashi

И уж тем более они обязательны, когда речь идет о выполнении программы в многопоточной среде (то бишь давно уже «всегда»).

Даже для атомарных типов? А что делать, когда многопоточие сильно многопоточное? Мьютексы - они, как бы, не шибко многопоточности способствуют.

mv ★★★★★
()
Ответ на: комментарий от mv

Даже для атомарных типов?

Значение атомарных типов, например в яве кешируется, и никто не гарантирует что int будет в обоих потоках (даже не процессорах) иметь одинаковое значение.

А что делать, когда многопоточие сильно многопоточное?

Нешто переходить от сеттеров к публичным полям?

wfrr ★★☆
()
Ответ на: комментарий от no-dashi

no-dashi(28.03.2010 23:27:44)> Реализуй без сеттеров в том или ином виде пункт 4. Ждем-с, да.

Итак: 4. Реализовать обратную связь, когда при изменении ширины, высоты или положения объекта он перерисовывается на экране

Следи за руками:

public interface Updateable {
    void refresh();
}

public interface Dragger extends Updateable {
    void move(int toX, int toY);
}

public interface Resizeable extends Updateable {
    void resize(int deltaX, int deltaY);
}

public class Unit implements Dragger, Resizeable {

    int x, y, width, height;

    private Canvas c;//впрочем, вместо Canvas мог быть любой другой приёмник сообщений о том, что что-то случилось с объектом класса Unit

    public Unit(Canvas c) {
        this.c = c;
    }

    public void move(int toX, int toY) {
        this.x = toX;
        this.y = toY;
        refresh();
    }

    public void resize(int deltaX, int deltaY) {
        int w = width + deltaX;
        int h = height + deltaY;
        if (w < 0 || h < 0)
            throw new IllegalStateException("Размер объекта не может быть отрицательным ни по одной из размерностей.");
        this.width = w;
        this.height = h;
        refresh();
    }

    public void refresh() {
    // ...сигнал об обновлении на c
    }
}

Клиентский код:

Unit unit = new Unit(canvas);
...
Dragger d = unit;
d.move(100, 200);
...
Resizeable r = unit;
r.resize(-15, 30);
...
unit.refresh();//ручник, если что-то не в порядке

Идиот тот, кто не понимает, что get/set это фактически единственный унифицированный механизм контролировать доступ к атрибутам класса, что необходимо и обязательно в ситуации, когда код используется, сопровождается и поддерживается более чем одним человеком. И уж тем более они обязательны, когда речь идет о выполнении программы в многопоточной среде (то бишь давно уже «всегда»).

no-dashi, ты здесь слил. Признай это немедленно и беспрекословно.

iZEN ★★★★★
()
Ответ на: комментарий от wfrr

Значение атомарных типов, например в яве кешируется, и никто не гарантирует что int будет в обоих потоках (даже не процессорах) иметь одинаковое значение.

В яве... tailgunner букварь Дреппера всем рекомендует, тебе тоже бы надо порекомендовать...

А что делать, когда многопоточие сильно многопоточное?

Нешто переходить от сеттеров к публичным полям?

Легко. RCU, и мьютексы в *еттерах вместе с самими *еттерами для smp более не нужны.

mv ★★★★★
()
Ответ на: комментарий от mv

В яве... tailgunner букварь Дреппера всем рекомендует, тебе тоже бы надо порекомендовать...

Я какбе ограничиваюсь чтением спецификации, найдете там строчку говорящую иное?

Легко. RCU, и мьютексы в *еттерах вместе с самими *еттерами для smp более не нужны.

Легко. Привет глюки. Ога.

wfrr ★★☆
()
Ответ на: комментарий от wfrr

Если ЛОР это соцсеть то кто выигрывает от общения? lenta.ru/news/2010/03/05/social/

Karapuz ★★★★★
()
Ответ на: комментарий от wfrr

Я какбе ограничиваюсь чтением спецификации, найдете там строчку говорящую иное?

Хотелось бы почитать такую спецификацию, в которой сказано, что когерентность памяти в пределах двух контекстов на одном ядре не гарантируется. А также, как с этим жить.

Легко. Привет глюки. Ога.

Какие?

mv ★★★★★
()
Ответ на: комментарий от wfrr

Значение атомарных типов, например в яве кешируется, и никто не гарантирует что int будет в обоих потоках (даже не процессорах) иметь одинаковое значение.

В Яве не для всех простых типов операции в потоках атомарны.

iZEN ★★★★★
()
Ответ на: комментарий от mv

Хотелось бы почитать такую спецификацию, в которой сказано, что когерентность памяти в пределах двух контекстов на одном ядре не гарантируется.

JLS (хе, щас поуглил, я протухшую спецификацию читал, теперь есть ровно один способ избежать этого)

А также, как с этим жить.

и он зовется volatile

Какие?

Вам ли не знать? Или вы ни одной мультипоточной программы не пейсали?

wfrr ★★☆
()
Ответ на: комментарий от wfrr

> Значение атомарных типов, например в яве кешируется, и никто не гарантирует что int будет в обоих потоках (даже не процессорах) иметь одинаковое значение.

даже при volatile? //привет от нечитающих спецификации ;)

qnikst ★★★★★
()
Ответ на: комментарий от iZEN

no-dashi, ты здесь слил. Признай это немедленно и беспрекословно.

Какой феерический пипец. Ты просто реализуй в своем коде логику resize(), в котором новый размер задан не как «дельта», а как абсолютный размер. Уточнение - реализовывает эту логику тот, кому ты не предоставил исходник.

class Rect {
    int width;
    int height;
    public void setWidth(int w) { if (width!=w) { width=w; emitChangedSignal(); } }
    public void getWidth() { return width; }
    public void setHeight(int h) { if(height!=h) { height=h; emitChangedSignal(); } }
    public void getHeight() { return height; }
    public void resize(int w, int h) { width=w; height=h; emitChangedSignal(); }
}

Вдруг поняли что resize должен быть «атомарным» по сигналам, то есть эмитить один сигнал на изменение размера, а не два сигнала - на изменение ширины и изменение высоты? Без проблем:

class Rect{
    int width;
    int height;
    public void setWidth(int w) { if (getWidth()!=w) resize(w,getHeight()); }
    public void getWidth() { return width; }
    public void setHeight(int h) { if(height!=h) resize(getWidth(),h); } }
    public void getHeight() { return height; }
    void resize(int w, int h) { width=w; height=h; emitChangedSignal(); }
}
И о, чудо - никто из дергавших методы снаружи не заметил, что логика внутри изменилась! Реализовать квадрат? Да без проблем:
class Square {
    public void setWidth(int w) { if (getWidth()!=w) resize(w,w) }
    public void setHeight(int h) { if (getHeight()!=h) resize(h,h); }
}
А теперь сравни это со своей лапшой из интерфейсов.

P.S.: Насколько я понимаю, ты еще и относишься к той категории школьников, которые говорят что Qt это объектно-ориентированный тулкит, а GTK не объектно-ориентирован?

no-dashi ★★★★★
()
Ответ на: комментарий от jtootf

> пример утрированный

к примеру могут быть возражения (почему высота устанавливается в 0, можно было бы и в ширину), можно придумать и получше

- NewRect надо было бы превратить в эллипс

- интерфейс у эллипса в точности тот же, что у прямоугольника

- добавить функцию NewRect NewRect::intersection(const NewRect&) const

и теперь главное — в проекте *неявно* предполагалось, что площадь пересечения двух прямоугольников это в точности площадь того прямоугольника, который выдается функцией intersection, поэтому спец. функция area_of_intersection не писалась, везде было r1.intersection(r2).area()

впрочем, на с++ тут можно костыль поставить (сделать новый класс «пересечение эллипсов» и возращать его, кроме того, неявно его преобразовывать в NewRect когда это возможно), а вот на яве?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

мой пример, впрочем, тоже не самый лучший, предлагаю придумать получше

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от mv

> Мьютексы - они, как бы, не шибко многопоточности способствуют.

Где вас таких берут? Per-instance mutex это почти единственный способ обеспечить вменяемую многопоточность. 1000 объектов, 500 нитей и 50 очередей? Без проблем, отдельными мутексами запираются операции с каждой из очередей и с каждым объектом, в результате нить блокируется в том и только том случае и на в точности то время, пока другая нить оперирует с этим же объектом или с этой же очередью. Примерно такой подход применяется в ядрах операционок в модели драйверов, за счет чего становится возможной например параллельная запись и чтение на нескольки устройствах, и сохраняется когерентность очередей.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

Ты просто реализуй в своем коде логику resize(), в котором новый размер задан не как «дельта», а как абсолютный размер. Уточнение - реализовывает эту логику тот, кому ты не предоставил исходник.

Следи за руками (старые классы не изменились; добавилась «косметика»):

public interface Updateable {
	void refresh();
}
--------------------------------------------------
public interface Dragger {
	void move(int toX, int toY);
}
--------------------------------------------------
public interface Resizeable {
	void resize(int deltaX, int deltaY);
}
--------------------------------------------------
import java.io.PrintStream;

public class Unit implements Dragger, Resizeable {

	int x, y, width, height;

	private PrintStream ps;// приёмник сообщений о том, что что-то случилось с объектом класса Unit

	public Unit(PrintStream ps) {
		this.ps = ps;//косметика
	}

	public void move(int toX, int toY) {
		this.x = toX;
		this.y = toY;
		refresh();
	}

	public void resize(int deltaX, int deltaY) {
		int w = width + deltaX;
		int h = height + deltaY;
		if (w < 0 || h < 0)
			throw new IllegalStateException(
					"Размер объекта не может быть отрицательным ни по одной из размерностей.");
		this.width = w;
		this.height = h;
		refresh();
	}

	public void refresh() {
		ps.printf("ClassName: %s\nРазмеры: x=%d y=%d width=%d height=%d\n", this.getClass(), x, y, width, height);//косметика
	}
}
Наша новая сущность:
public interface Resizeable2 extends Resizeable {
	void resize(int width, int height);
	void resize(int size);
}
Наш класс:
import java.io.PrintStream;

public class Rectangle extends Unit implements Resizeable2 {
	public Rectangle(PrintStream c) {
		super(c);
	}

	public void resize(int width, int height) {
		this.width = width;
		this.height = height;
		refresh();
	}

	public void resize(int size) {
		this.width = size;
		this.height = size;
		refresh();
	}
}
Клиентский класс:
import java.io.PrintStream;

public class Square extends Rectangle {

	public Square(PrintStream c) {
		super(c);
	}

	public void resize(int width, int height) {
		if (width != height)
			throw new UnsupportedOperationException(
					"Квадрат не может иметь разные стороны.");
		super.resize(width);
	}
}
Тест:
public class FigureTest {
	public static void main(String[] args) {
		Unit unit = new Unit(System.out);
		Dragger d = unit;
		d.move(100, 200);
		Resizeable r = unit;
		//r.resize(-15, 30);//java.lang.IllegalStateException: Размер объекта не может быть отрицательным ни по одной из размерностей.
		r.resize(15, 30);
		unit.refresh();// ручник, если что-то не в порядке
		unit.resize(10, 10);
		//...
		Rectangle rect = new Rectangle(System.out);
		rect.resize(20, 20);
		rect.resize(-70, 80);
		//...
		Square quad = new Square(System.out);
		quad.resize(50);
		quad.resize(40, 40);
		//quad.resize(-17, -15);//java.lang.UnsupportedOperationException: Квадрат не может иметь разные стороны.
	}
}
Вывод:
ClassName: class Unit
Размеры: x=100 y=200 width=0 height=0
ClassName: class Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class Unit
Размеры: x=100 y=200 width=25 height=40
ClassName: class Rectangle
Размеры: x=0 y=0 width=20 height=20
ClassName: class Rectangle
Размеры: x=0 y=0 width=-70 height=80
ClassName: class Square
Размеры: x=0 y=0 width=50 height=50
ClassName: class Square
Размеры: x=0 y=0 width=40 height=40
(Здесь так и напрашивается объявить CheckedException для метода resize(...) и исключения на отрицательную размерность, чтобы усилить контракт для полиморфного метода. .NET-разработчики этого лишены. Но это — дело вкуса.)

А в твоём случае придётся перекомпилировать всю иерархию, так как малейшее изменение родительского класса. Например, ты решил добавить новый метод в класс Rect, а у некоторых клиентов сигнатура этого метода совпала с твоим, и тут начинается глюкодром ВНЕЗАПНО полиморфных вызовов...

Вдруг поняли что resize должен быть «атомарным» по сигналам, то есть эмитить один сигнал на изменение размера, а не два сигнала - на изменение ширины и изменение высоты?

У меня изначально так и есть. А вот почему ты решил, что нужно сначала наступить на эти грабли с рассылкой уведомлений во время фактически неконсистентного состояния объекта от отдельных изменений полей, получить по лбу и лишь затем взяться за рефакторинг? Может это как раз то, ЧТО любителя отличает от эксперта и/или ЧТО любители любят списывать на синдром преждевременной оптимизации?

А теперь сравни это со своей лапшой из интерфейсов.

Я показал, что компоновка (mixin) лучше и гибче наследования.

iZEN ★★★★★
()
Ответ на: комментарий от no-dashi

>Насколько я понимаю, ты еще и относишься к той категории школьников, которые говорят что Qt это объектно-ориентированный тулкит, а GTK не объектно-ориентирован?

ВНЕЗАПНО: я не нахожу между ними разницы, кроме визуально-лук'and'фильного кошмара Qt4.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN
public class Rectangle extends Unit implements Resizeable2 { 
 
   public void resize(int width, int height) { 
      this.width = width;  <---
      this.height = height; <---
      refresh(); 
   }

Все, сисадминишка, далее с тобой разговаривать не имеет смысла. Твои приватные width и height видимы только в рамках того же пакета, все остальные классы их не видят. И когда _другой_ разработчик начнет наследоваться от твоего класса, его ждет бааальшой облом, и он начнет желать тебе ректального наказания.

А если ты «высветишь» эти мемеберы через protected, то возможно прямое присваивание значений им из порожденного наследованием класса, что даст возможность нарушить модельную целостность «квадрата», когда ширина квадрата не равна высоте квадрата.

Иди фапай и микси дальше.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

А мы не привередливые

Давай перенесём интерфейсы Updateable, Dragger, Resizeable, Resizeable2 и классы разработчика Unit и Rectangle в пакет devpackage. А клиентские классы в clientpackage.

Тогда:

package clientpackage;

import java.io.PrintStream;
import devpackage.Rectangle;

public class Square extends Rectangle {

	public Square(PrintStream c) {
		super(c);
	}

	public void resize(int width, int height) {
		if (width != height)
			throw new UnsupportedOperationException(
					"Квадрат не может имееть разные стороны.");
		super.resize(width);
	}
}
--------------------------------------------------
package clientpackage;

import devpackage.*;

public class FigureTest {
	public static void main(String[] args) {
		Unit unit = new Unit(System.out);
		Dragger d = unit;
		d.move(100, 200);
		Resizeable r = unit;
		//r.resize(-15, 30);//java.lang.IllegalStateException: Размер объекта не может быть отрицательным ни по одной из размерностей.
		r.resize(15, 30);
		unit.refresh();// ручник, если что-то не в порядке
		unit.resize(10, 10);
		//...
		Rectangle rect = new Rectangle(System.out);
		rect.resize(20, 20);
		rect.resize(-70, 80);
		//...
		Square quad = new Square(System.out);
		quad.resize(50);
		quad.resize(40, 40);
		//quad.resize(-17, -15);//java.lang.UnsupportedOperationException: Квадрат не может иметь разные стороны.
	}
}
— код не изменился! Выхлоп:
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=0 height=0
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=25 height=40
ClassName: class devpackage.Rectangle
Размеры: x=0 y=0 width=20 height=20
ClassName: class devpackage.Rectangle
Размеры: x=0 y=0 width=-70 height=80
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=50 height=50
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=40 height=40
— тоже.

iZEN ★★★★★
()
Ответ на: комментарий от no-dashi

>this.width = width; <---

this.height = height; <---


Не тупи. Здесь они «постольку поскольку» УЖЕ_ЕСТЬ. У каждого клиентского класса они могут быть свои, затеняя родительские или не затеняя, тем не менее работа полиморфных методов не будет нарушена (если поля родительского класса не видны из другого пакета, то кто ж их нарушит? Ж))

iZEN ★★★★★
()
Ответ на: комментарий от no-dashi

в результате нить блокируется в том и только том случае и на в точности то время, пока другая нить оперирует с этим же объектом или с этой же очередью.

1 объект, 500 нитей. 250 нитей читают, а 250 пишут. И как оно с «почти единственным способом» будет работать?

mv ★★★★★
()
Ответ на: комментарий от no-dashi

> Per-instance mutex это почти единственный способ обеспечить вменяемую многопоточность.

Жж0ш. Ты хоть слышал об Occam и/или CSP?

отдельными мутексами запираются операции с каждой из очередей и с каждым объектом

Это как, хотя бы псевдокод можно? А то про запирание операций с очередью понятно, но причем тут операции с объектом - уже нет. Что ты называешь per-instance mutex - тоже становится непонятно.

tailgunner ★★★★★
()
Ответ на: комментарий от iZEN

немного вопросов: 1). как данную фигуру сдвинуть на 10px влево? если ты реализуешь getX и getY это твоя реализация будет обычной реализацией сеттеров/геттеров, только в профиль.

2). ну про square extends rectangle про это лучше просто молчать, но данная тема вообще непонятно почему поднялась, так что это лирика

qnikst ★★★★★
()

Когда надо будет сопровождать чужой код объёмом более 10mb, сам поймёшь :) Если серьёзно - однозначного ответа нет, для многих классов get/set это мастхэв, в других случаях это более чем избыточно.

runtime ★★★★
()
Ответ на: комментарий от iZEN

Ещё один клиентский класс:

package otherclientpackage;

import java.io.PrintStream;
import devpackage.Rectangle;

public class Ellipse extends Rectangle {

	private PrintStream ps;

	public Ellipse(PrintStream ps) {
		super(ps);
		this.ps = ps;
	}

	public void refresh() {
		super.refresh();
		ps.println("Овал рефрешнулся.");
	}
}
--------------------------------------------------
package clientpackage;

import devpackage.*;
import otherclientpackage.Ellipse;

public class FigureTest {
	public static void main(String[] args) {
		Unit unit = new Unit(System.out);
		Dragger d = unit;
		d.move(100, 200);
		Resizeable r = unit;
		// r.resize(-15, 30);//java.lang.IllegalStateException: Размер объекта
		// не может быть отрицательным ни по одной из размерностей.
		r.resize(15, 30);
		unit.refresh();// ручник, если что-то не в порядке
		unit.resize(10, 10);
		// ...
		Rectangle rect = new Rectangle(System.out);
		rect.resize(20, 20);
		rect.resize(-70, 80);
		// ...
		Square quad = new Square(System.out);
		quad.resize(50);
		quad.resize(40, 40);
		// quad.resize(-17, -15);//java.lang.UnsupportedOperationException:
		// Квадрат не может иметь разные стороны.
		// ...
		System.out.println("Строим овал.");
		Ellipse el = new Ellipse(System.out);
		el.resize(150, 50);
	}
}
Выхлоп:
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=0 height=0
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=15 height=30
ClassName: class devpackage.Unit
Размеры: x=100 y=200 width=25 height=40
ClassName: class devpackage.Rectangle
Размеры: x=0 y=0 width=20 height=20
ClassName: class devpackage.Rectangle
Размеры: x=0 y=0 width=-70 height=80
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=50 height=50
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=40 height=40
Строим овал.
ClassName: class otherclientpackage.Ellipse
Размеры: x=0 y=0 width=150 height=50
Овал рефрешнулся.
Как видишь, родительские поля width и height здесь вообще «не видны, а они есть.» © Бурундук

Научись обходится без того, без чего (так ли нужен доступ к полям?) ты можешь обходиться.

iZEN ★★★★★
()
Ответ на: комментарий от no-dashi

не парься, ещё несколько итераций и iZEN таки напишет более-менее вменяемую реализацию, с отличными геттерами вида getX(),getY() и сеттером move(.,.). Утверждая, что move это не сеттер а мега-вещь способная изменить мир.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

> iZEN таки напишет более-менее вменяемую реализацию, с отличными геттерами вида getX(),getY()

Ты можешь объяснитьь, зачем здесь геттеры?

и сеттером move(.,.). Утверждая, что move это не сеттер

А это и не сеттер - в нем есть вызов refresh().

P.S. и заметь - только и iZEN хватило духа предъявить код :)

tailgunner ★★★★★
()
Ответ на: комментарий от qnikst

>немного вопросов:

Прекрасно.

1). как данную фигуру сдвинуть на 10px влево? если ты реализуешь getX и getY это твоя реализация будет обычной реализацией сеттеров/геттеров, только в профиль.


Да, но у get()/set() слишком широкие возможности, которые могут и часто используются небезопасно. Они нарушают целостность и последовательность состояния целого объекта.

Метод move(toX, toY) работает с АБСОЛЮТНЫМИ координатами и, практически атомарно с состоянием объекта. Это — контракт обусловлен интерфейсом Dragger. Хотите расширить контракт — расширяйте интерфейс и реализуйте его без использования слишком тонких инструментов в виде геттеров/сеттеров.

iZEN ★★★★★
()
Ответ на: комментарий от qnikst

> данная тема вообще непонятно почему поднялась

Данная тема поднялась в качестве иллюстрации того, что бывает, если заявить *еттеры как часть интерфейса. Просто лоровская школота как обычно не смогла разглядеть за деревьями леса. У неё случился разрыв шаблона:

А Вы только посмотрите какой инопланетный у него код - там высота квадрата равна нулю!


Очевидно, с точки зрения отдельных лоровцев любой гиперкуб должен быть реализована через массив идентичной размерности, заполенный одним и тем же значением. )))

LamerOk ★★★★★
()
Ответ на: комментарий от qnikst

2). ну про square extends rectangle про это лучше просто молчать

Почему?

Дочерние классы, как правило, должны детализировать функциональность (от абстракции до финального класса реализации Ж).

iZEN ★★★★★
()
Ответ на: комментарий от tailgunner

> Ты можешь объяснитьь, зачем здесь геттеры?

например - реализация столкновения фигур, или сдвиг фигуры относительно точки, где она находится.

А это и не сеттер - в нем есть вызов refresh().

Вау :) нууу, если под сеттером понимать только функции вида void setX(T x) { this.x = X; } то да, наверное у противников сеттеров есть резон так говорить.

Это сеттер. Обычный такой сеттер.

то что хватило духу, это очень большой плюс, хотелось бы заметить, что тут не только iZEN код приводил, правда там с сеттерами было.

qnikst ★★★★★
()
Ответ на: комментарий от iZEN

у тебя слишком узкое понимание сеттеров и геттеров, такие какие они в твоём понимании они не нужны.

Интерфейсы тут не причём, это ортогональные понятия.

интерфейс вида

 
interface Draggable {
  int getX();
  int getY();
  synchronized void move(int x,int y);
  synchronized void moveBy(int x,int y);
}

является интерфейсом с 2мя геттерами и одним сеттером для двух полей. возражения?

qnikst ★★★★★
()
Ответ на: комментарий от iZEN

>>2). ну про square extends rectangle про это лучше просто молчать

Почему?


Потому что square накладывает ограничения на rectangle так, что не может заменить его в любом месте, где он используется. Любая функция, использующая какой-то класс, должна правильно работать, если вместо этого класса будет его наследник. В твоём примере это не так.

Laz ★★★★★
()
Ответ на: комментарий от iZEN

Дочерние классы, как правило, должны расширять возможности данного класса, при этом не устанавливая новых правил :)

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

>> Ты можешь объяснитьь, зачем здесь геттеры?

например - реализация столкновения фигур, или сдвиг фигуры относительно точки, где она находится.

Столкновение - это уже придумывание новых usecase'ов, сдвиг - еще один метод.

А это и не сеттер - в нем есть вызов refresh().

Вау :) нууу, если под сеттером понимать только функции вида void setX(T x) { this.x = X; } то да, наверное у противников сеттеров есть резон так говорить.

Это сеттер. Обычный такой сеттер.

Вау. Нуу, если под сеттером понимать метод, который меняет внутренние пременные класса, то тогда сеттером можно обозвать очень многое (а всё остальное - геттерыом).

тут не только iZEN код приводил

А кто еще? Код, который привел shty - пустой флуд.

tailgunner ★★★★★
()
Ответ на: комментарий от Laz

> Потому что square накладывает ограничения на rectangle так, что не может заменить его в любом месте, где он используется.

Интересно. А тебе не кажется, что если пойти другим путем (Rectangle extends Square), то сломается код, завязанный на равенство сторон квадрата? Не является ли ослабление инварианта нарушением принципа Лисков?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Интересно. А тебе не кажется, что если пойти другим путем (Rectangle extends Square), то сломается код, завязанный на равенство сторон квадрата? Не является ли ослабление инварианта нарушением принципа Лисков?
Я считаю, что rectangle и square не связаны между собой отношениями наследования. Разве что они расширяют какой-нибудь класс shape, но это уже не отношение.

Laz ★★★★★
()
Ответ на: комментарий от qnikst

>является интерфейсом с 2мя геттерами и одним сеттером для двух полей. возражения?

Слишком широкие интерфейсы не нужны. Они не представляют контракта как такового (большие полномочия). Их сложно поддерживать внутренне согласованными в реализующих их классах.

Контракт представляет собой предикат, то есть утверждение что делать МОЖНО с объектом.

Смешивать методы «интроспекции» состояния (getX(), getY()) с методами изменения состояния объекта (move(...)) — плохая затея. Лучше специфицировать два отдельных интерфейса, один из которых специфицирует методы чтения состояния, а другой специфицирует методы изменения состояния. В этом случае после создания объекта, реализующего методы обоих интерфейсов, возможно его ИСПОЛЬЗОВАНИЕ как в режиме Read-Only(RO), так и в режимах RW и WO, что важно в программных системах с разделением полномочий.

iZEN ★★★★★
()
Ответ на: комментарий от qnikst

>Дочерние классы, как правило, должны расширять возможности данного класса, при этом не устанавливая новых правил :)

Тебе ещё не объяснили, что из класса Point путём наследования получать Circle, а из Circle получать дочерний класс Ellipse — плохая идея? Ж))

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Они нарушают целостность и последовательность состояния целого объекта.

мантра для криворуких индусопрограммистов

shty ★★★★★
()
Ответ на: комментарий от iZEN

ты прав с точностью до наоборот. литературу чтоли почитай

qnikst ★★★★★
()
Ответ на: комментарий от Laz

Потому что square накладывает ограничения на rectangle так, что не может заменить его в любом месте, где он используется.

Может. Квадрат есть Прямоугольник и может заменить его там, где нужен Прямоугольник. Принцип подстановки Лисков сохраняется.

Не всякий Прямоугольник является Квадратом, поэтому наследовать Прямоугольник от Квадрата — глупость.

Любая функция, использующая какой-то класс, должна правильно работать, если вместо этого класса будет его наследник. В твоём примере это не так.

Это так. Иначе тест сломался бы.

iZEN ★★★★★
()
Ответ на: комментарий от Laz

>> Интересно. А тебе не кажется, что если пойти другим путем (Rectangle extends Square), то сломается код, завязанный на равенство сторон квадрата? Не является ли ослабление инварианта нарушением принципа Лисков?

Я считаю, что rectangle и square не связаны между собой отношениями наследования. Разве что они расширяют какой-нибудь класс shape, но это уже не отношение.

Их _можно_ не связывать отношениями наследования. Но можно и связать, это нормально - усиление инварианта в производных классах вполне согласуется с принципом Лисков.

tailgunner ★★★★★
()
Ответ на: комментарий от iZEN

Квадрат не может пользоваться функциями прямоугольника, поскольку они могут вывести его из консистентного состояния, поскольку у квадрата есть дополнительные ограничения на возможные состояния. Решение запретить все функции изменения состояния ;) или переопределить их. В первом случае можно радостно получить огромное усложнение архитектуры, во втором ООП становится не нужно ;)

qnikst ★★★★★
()
Ответ на: комментарий от tailgunner

> Их _можно_ не связывать отношениями наследования.

наезд был именно на их связываения отношениями прямоугольник-наследование->квадрат.

Utils.расширитьВ2раза(Rectangle rect); будет работать с прямоугольником, но не будет с квадратом => нарушение принципа Лисков.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

> Utils.расширитьВ2раза(Rectangle rect); будет работать с прямоугольником, но не будет с квадратом => нарушение принципа Лисков.

А можно подробнее?

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.