Alexander 2 лет назад
Родитель
Сommit
151d77ee54

+ 20 - 0
06-классы-объектно-ориентированный-стиль/README.md

@@ -105,6 +105,8 @@ unittest
 
 Обратите внимание на небольшую хитрость. В приведенном коде использовано выражение `w.defaultName`, а не `Widget.defaultName`. Для обращения к статическому члену класса всегда можно вместо имени класса использовать имя экземпляра класса. Это возможно, потому что при обработке выражения слева от точки сначала выполняется разрешение имени и только потом идентификация объекта (если потребуется). Выражение w в любом случае вычисляется: будет оно использовано или нет.
 
+[Исходный код](src/chapter-6-1/)
+
 [В начало ⮍](#6-1-классы) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ## 6.2. Имена объектов – это ссылки
@@ -214,6 +216,8 @@ if (‹условие›)
 
 Сравним ссылочную семантику с семантикой значений а-ля `int`. У семантики значений есть свои преимущества, среди которых выделяется логический вывод: в выражениях всегда можно заменять равные значения друг на друга, при этом результат не изменяется. (А к ссылкам, использующим для изменения состояния объектов вызовы методов, такой подход неприменим.) Другое важное преимущество семантики значений – скорость. Но даже если вы воспользуетесь динамической щедростью полиморфизма, от ссылочной семантики никуда не деться. Некоторые языки пытались предоставить возможность использовать и ту, и другую семантику и заслужили прозвище «нечистых» (в противоположность чисто объектно-ориентированным языкам, использующим ссылочную семантику унифицированно для всех типов). D нечист и очень гордится этим. Во время разработки необходимо принять решение: если вы желаете работать с некоторым типом в рамках объектно-ориентированной парадигмы, следует выбрать тип `class`; иначе придется использовать тип `struct` и поступиться всеми удобствами ООП, присущими ссылочной семантике.
 
+[Исходный код](src/chapter-6-2/)
+
 [В начало ⮍](#6-2-имена-объектов-это-ссылки) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ## 6.3. Жизненный цикл объекта
@@ -239,6 +243,8 @@ unittest
 
 При вычислении выражения `new Test` конструируется объект типа `Test` с состоянием по умолчанию, то есть экземпляр класса `Test`, каждое из полей которого инициализировано своим значением по умолчанию. Любой тип `T` обладает статически известным значением по умолчанию, обратиться к которому можно через свойство `T.init` (значения свойств `.init` для базовых типов приведены в табл. 2.1). Если вы хотите инициализировать некоторые поля значениями, отличными от соответствующих значений свойства `.init`, укажите при определении этих полей статически известные инициализирующие значения, как показано в предыдущем примере для поля `a`. Выполнение теста модуля при этом не порождает исключений, так как это поле явно инициализируется константой `0.4`, а поле `b` не трогали, а значит, оно неявно инициализируется значением выражения `double.init`, то есть NaN («нечисло»).
 
+[Исходный код](src/chapter-6-3/)
+
 [В начало ⮍](#6-3-жизненный-цикл-объекта) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.3.1. Конструкторы
@@ -303,6 +309,8 @@ class NoGo
 
 Обычные правила перегрузки функций (раздел 5.5) применимы и к конструкторам: класс может определять любое количество конструкторов, но каждый из них должен обладать уникальной сигнатурой (отличающейся числом или типом параметров, хотя бы на один параметр).
 
+[Исходный код](src/chapter-6-3-1/)
+
 [В начало ⮍](#6-3-1-конструкторы) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.3.2. Делегирование конструкторов
@@ -722,6 +730,8 @@ unittest
 
 Если бы занявший место экземпляра класса `Contact` экземпляр класса `Friend` вел себя *в точности* так же, как и экземпляр ожидаемого класса, отпали бы все (или почти все) причины использовать класс `Friend`. Одно из основных средств, предоставляемых объектной технологией, – возможность классам-наследникам переопределять функции классов-предков и таким образом модульно настраивать поведение сущностей среды. Как можно догадаться, переопределение задается с помощью ключевого слова `override` (класс `Friend` переопределяет метод `bgColor`), которое обозначает, что вызов `c.bgColor()` (где вместо c ожидается объект типа `Contact`, но на самом деле используется объект типа `Friend`) всегда инициирует вызов версии метода, предлагаемой классом `Friend`. Друзья всегда остаются друзьями, даже если компилятор думает, что это обыкновенные контакты.
 
+[Исходный код](src/chapter-6-4/)
+
 [В начало ⮍](#6-4-методы-и-наследование) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.4.1. Терминологический «шведский стол»
@@ -902,6 +912,8 @@ void workWith(TextWidget tw)
 
 Чтобы максимизировать количество доступной статической информации о типах, D вводит средство, известное как *ковариантные возвращаемые типы*. Звучит довольно громко, но смысл ковариантности возвращаемых типов довольно прост: если родительский класс возвращает некоторый тип `C`, то переопределенной функции разрешается возвращать не только `C`, но и любого потомка `C`. Благодаря этому средству можно позволить методу `TextWidget.duplicate` возвращать `TextWidget`. Не менее важно, что теперь вы можете прибавить себе веса в дискуссии, вставив при случае фразу «ковариантные возвращаемые типы». (Шутка. Если серьезно, даже не пытайтесь.)
 
+[Исходный код](src/chapter-6-4-5/)
+
 [В начало ⮍](#6-4-5-ковариантные-возвращаемые-типы) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ## 6.5. Инкапсуляция на уровне классов с помощью статических членов
@@ -1140,6 +1152,8 @@ unittest
 
 Обратите внимание: вместе с именем класса возвращено и имя модуля, в котором класс был определен. По умолчанию модуль получает имя файла, в котором он расположен, но это умолчание можно изменить с помощью объявления с ключевым словом `module` (см. раздел 11.8).
 
+[Исходный код](src/chapter-6-8-1/)
+
 [В начало ⮍](#6-8-1-string-tostring) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.8.2. size_t toHash()
@@ -1882,6 +1896,8 @@ class Outer
 }
 ```
 
+[Исходный код](src/chapter-6-11/)
+
 [В начало ⮍](#6-11-вложенные-классы) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.11.1. Вложенные классы в функциях
@@ -2244,6 +2260,8 @@ class StorableShape : Shape
 }
 ```
 
+[Исходный код](src/chapter-6-13-1/)
+
 [В начало ⮍](#6-13-1-переопределение-методов-в-сценариях-множественного-порождения-подтипов) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ## 6.14. Параметризированные классы и интерфейсы
@@ -2325,6 +2343,8 @@ unittest
 
 Как только вы создадите экземпляр параметризированного класса, он превратится в обычный класс, так что `StackImpl!int` – это такой же класс, как и любой другой. Именно этот конкретный класс реализует `Stack!int`, поскольку в формочку для вырезания `StackImpl(T)` под видом `T` вставили `int` по всему телу этого класса.
 
+[Исходный код](src/chapter-6-14/)
+
 [В начало ⮍](#6-14-параметризированные-классы-и-интерфейсы) [Наверх ⮍](#6-классы-объектно-ориентированный-стиль)
 
 ### 6.14.1. И снова гетерогенная трансляция

+ 43 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-1/app.d

@@ -0,0 +1,43 @@
+class Widget
+{
+    // Константа
+    enum fudgeFactor = 0.2;
+
+    // Разделяемое неизменяемое значение
+    static immutable defaultName = "A Widget";
+
+    // Некоторое состояние, определенное для всех экземпляров класса Widget
+    string name = defaultName;
+    uint width, height;
+
+    // Статический метод
+    static double howFudgy()
+    {
+        return fudgeFactor;
+    }
+
+    // Метод
+    void changeName(string another)
+    {
+        name = another;
+    }
+
+    // Метод, который нельзя переопределить
+    final void quadrupleSize()
+    {
+        width *= 2;
+        height *= 2;
+    }
+}
+
+unittest
+{
+    // Обратиться к статическому методу класса Widget
+    assert(Widget.howFudgy() == 0.2);
+    // Создать экземпляр класса Widget
+    auto w = new Widget;
+    // Поиграть с объектом типа Widget
+    assert(w.name == w.defaultName); // Или Widget.defaultName
+    w.changeName("Мой виджет");
+    assert(w.name == "Мой виджет");
+}

+ 23 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-11/app.d

@@ -0,0 +1,23 @@
+class Outer
+{
+    int x;
+
+    class Inner
+    {
+        int y;
+
+        this()
+        {
+            x = 42;
+            // x – то же, что this.outer.x
+            assert(this.outer.x == 42);
+        }
+    }
+}
+
+unittest
+{
+    auto outer = new Outer;
+    auto inner = outer.new Inner;
+    assert(outer.x == 42); // Вло­жен­ный объ­ект inner из­ме­нил внеш­ний объ­ект outer
+}

+ 60 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-13-1/app.d

@@ -0,0 +1,60 @@
+import std.stdio : writeln;
+
+class Shape
+{
+    protected string _name;
+    abstract void print();
+}
+
+class DBObject
+{
+    protected string _name;
+    abstract void print();
+    void saveState()
+    {
+        writeln(_name);
+    }
+}
+
+class StorableShape : Shape
+{
+    private class MyDBObject : DBObject
+    {
+        this(string name)
+        {
+            _name = name;
+        }
+
+        override void print()
+        {
+            writeln(_name);
+        }
+
+        final override void saveState()
+        {
+            writeln(this.outer._name, "; ", _name);
+        }
+    }
+
+    private MyDBObject _store;
+    alias _store this;
+
+    this(string outName, string inName)
+    {
+        _name = outName;
+        _store = new MyDBObject(inName);
+    }
+    
+    override void print()
+    {
+        writeln(_name);
+    }
+}
+
+void main()
+{
+    auto s = new StorableShape("first", "second");
+    s.print();          // StorableShape._name
+    s._store.print();   // StorableShape.MyDBObject._name
+    s.saveState();      // StorableShape._name and StorableShape.MyDBObject._name
+}

+ 50 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-14/app.d

@@ -0,0 +1,50 @@
+import std.array;
+
+interface Stack(T)
+{
+    @property bool empty();
+    @property ref T top();
+    void push(T value);
+    void pop();
+}
+
+class StackImpl(T) : Stack!T
+{
+    private T[] _store;
+
+    @property bool empty()
+    {
+        return _store.empty;
+    }
+
+    @property ref T top()
+    {
+        assert(!empty);
+        return _store.back;
+    }
+
+    void push(T value)
+    {
+        _store ~= value;
+    }
+
+    void pop()
+    {
+        assert(!empty);
+        _store.popBack();
+    }
+}
+
+void main()
+{
+    auto stack = new StackImpl!int;
+    assert(stack.empty);
+    stack.push(3);
+    assert(stack.top == 3);
+    stack.push(5);
+    assert(stack.top == 5);
+    stack.pop();
+    assert(stack.top == 3);
+    stack.pop();
+    assert(stack.empty);
+}

+ 29 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-2/app.d

@@ -0,0 +1,29 @@
+import std.stdio;
+
+class A
+{
+    int x = 42;
+}
+
+unittest
+{
+    {
+        auto a1 = new A;
+        assert(a1.x == 42);
+        auto a2 = a1;
+        a2.x = 100;
+        assert(a1.x == 100);
+    }
+    {
+        auto a1 = new A;
+        auto a2 = new A;
+        a1.x = 100;
+        a2.x = 200;
+        // Заставим a1 и a2 обменяться привязками
+        auto t = a1;
+        a1 = a2;
+        a2 = t;
+        assert(a1.x == 200);
+        assert(a2.x == 100);
+    }    
+}

+ 23 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-3-1/app.d

@@ -0,0 +1,23 @@
+import std.math;
+
+class Test
+{
+    double a = 0.4;
+    double b;
+
+    this(int b)
+    {
+        this.b = b;
+    }
+
+    this() {}
+}
+
+unittest
+{
+    auto t = new Test(5);
+    auto z = new Test;
+
+    assert(t.b == 5);
+    assert(isNaN(z.b));
+}

+ 14 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-3/app.d

@@ -0,0 +1,14 @@
+import std.math;
+
+class Test
+{
+    double a = 0.4;
+    double b;
+}
+
+unittest
+{
+    // Объект создается с помощью выражения new
+    auto t = new Test;
+    assert(t.a == 0.4 && isNaN(t.b));
+}

+ 31 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-4-5/app.d

@@ -0,0 +1,31 @@
+class Widget
+{
+    this(Widget source)
+    {
+
+    }
+
+    Widget duplicate()
+    {
+        return new Widget(this); // Вы­де­ля­ет па­мять и вы­зы­ва­ет this(Widget)
+    }
+}
+
+class TextWidget : Widget
+{
+    this(TextWidget source)
+    {
+        super(source);
+    }
+
+    override TextWidget duplicate()
+    {
+        return new TextWidget(this);
+    }
+}
+
+void main()
+{
+    TextWidget tw;
+    TextWidget clone = tw.duplicate();
+}

+ 39 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-4/app.d

@@ -0,0 +1,39 @@
+class Contact
+{
+    string bgColor()
+    {
+        return "Серый";
+    }
+}
+
+class Friend : Contact
+{
+    string currentBgColor = "Светло-зеленый";
+    string currentReminder;
+
+    this(ref string c)
+    {
+        currentBgColor = c;
+    }
+
+    override string bgColor()
+    {
+        return currentBgColor;
+    }
+
+    string reminder()
+    {
+         return currentReminder;
+    }
+}
+
+unittest
+{
+    string startColor = "Синий";
+    Friend f = new Friend(startColor);
+    Contact c = f;            // Подставить экземпляр класса Friend вместо экземпляра класса Contact
+    auto color = c.bgColor(); // Вызвать метод класса Friend
+
+    import std.stdio : writeln;
+    writeln(color);    
+}

+ 8 - 0
06-классы-объектно-ориентированный-стиль/src/chapter-6-8-1/app.d

@@ -0,0 +1,8 @@
+module test;
+
+class Widget {}
+
+unittest
+{
+    assert((new Widget).toString() == "test.Widget");
+}