Упражнения и задачи за по - добро усвояване на OOP

C++ JAVA
User avatar
dakata__92
Web-tourist
Web-tourist
Posts: 3260
Joined: Tue Aug 02, 2011 7:24 pm
Answers: 126

Post by dakata__92 » Wed Mar 08, 2017 8:08 pm

pix3l wrote:Наследяването не е задължително, но е препоръчително да се използва, когато има очевидна връзка между класовете и единия може да допълни другия.

Имам един въпрос: За какво служат празните интерфейси? :D
Те са полезни точно толкова, колкото и тези, в които имаш методи, които трябва да се имплементират. :D
Чакай първо да се уточним. С твоят код ти обясняваш полиморфизъм. Взаимствано от твоят коментар, промених минимално кодат ти за да обясня шаблона фабрика. Нека разграничим първо двете обяснения. Ти наследяваш структурата, аз пък задължавам кода да съдържа метода с дадено име.

За теб класът Animal бива наследяван от подкласовете на Lion, Snake и Еagle и всеки изпълнява метода move. За целта ти правиш инстанция на класовете и един по един ги подаваш, като обекти на тестовият клас, и те стават параметри на метода move. Те задължително трябва да са от наследствената структура на Animal.

Аз имам интерфейс Анимал задължаващ класовете Lion, Snake и Еagle, които го имплементират, да съдържат в себе си метод с наименованието move. При мен се прави инстанция единствено на Тестовият клас и на него подавам имената (string) на класовете, като параметри на метода move. В този метод се решава дали да подаденият стринг е съществуващ клас и дали е имплементирал интерфейса Animal. Ако всичко е наред се създавa инстанция и метода move се изпълнява.

Въпреки, че има видима структура, НЕ е задължително да се използва унаследяване. Ти виждаш последователна структура с клас майка, докато някой друг може да види нуждата единствено от наличието на даден метод с определени параметри. Ти имаш нуждата наследника да изпълнява метод move дали на предшественика, дали негова интерпретация, решението ще е на база логика на приложението ти, докато на друг човек му е нужно този клас да има задължително собствен метод move без да има предшественик. Въпрос на гледна точка, дори различна, тя не е грешна, защото няма стандарт кога кое да се използва, има само препоръки. Всичко зависи от блок схемата на приложението и първоначално създадената структура.

Относно празните интерфейси те са безполезни, също като празните класове майки, които се наследяват. Хората си оставят възможността да задължат имплементиращите класове да имат определен метод използван някъде в приложението, докато добавянето на метод в празен клас майка, пък добавя логиката му, като опция за ползване при всички деца. В структурата с наследяване имаш опцията да използваш логиката на дефаутовият метод или да го презапишеш, докато с интерфейсите ти задължаваш класът просто да има такъв метод, без да даваш на наследниците опцията за дефаутова логика или да те интересува каква логика се съдържа в него.

Мой ред е да задам въпрос. :D :P
Ако метода move трябва да приема два параметъра, как ще задължиш наследниците при extend да използват тези два подадени параметъра? Те откъде ще знаят колко параметъра при презаписване на метода са нужни да приемат или дали да са public, protected и private?

[php]
<?php

class A
{
public function move($empty,$string)
{
if (isset($empty) and isset($string)) {
print "<br>A ".$empty." ".$string;
}
}
}

class B extends A
{
public function move()
{
print "<br>B";
}
}

class C extends A
{

}

(new B)->move("параметър 1","параметър 2");
(new C)->move("параметър 1","параметър 2");
[/php]

Ето така:

[php]
<?php
interface I
{
public function move($empty,$string);
}

class A implements I
{
public function move($empty,$string)
{
if (isset($empty) and isset($string)) {
print "<br>A ".$empty." ".$string;
}
}
}

class B implements I
{
public function move()
{
print "<br>B";
}
}

class C implements I
{

}

(new A)->move("параметър 1","параметър 2");
(new B)->move("параметър 1","параметър 2");
(new C)->move("параметър 1","параметър 2");
[/php]

или така

[php]
interface I
{
public function move($empty,$string);
}

class A implements I
{
public function move($empty,$string)
{
if (isset($empty) and isset($string)) {
print "<br>A ".$empty." ".$string;
}
}
}

class B extends A
{
public function move()
{
print "<br>B";
}
}

class C extends A
{

}

(new B)->move("параметър 1","параметър 2");
(new C)->move("параметър 1","параметър 2");
[/php]


Естествено съм сложил примери и методите им,може да се добавят или премахват или каквото Ви дойде на акъл за теста.

pix3l
Нов
Нов
Posts: 161
Joined: Sat Oct 08, 2016 2:31 pm

Post by pix3l » Wed Mar 08, 2017 8:31 pm

Лично аз бих използвал абстрактен метод...
Такъв бих използвал и при Animal, докато пишех примера, но не сметнах за нужно да усложнявам, тъй като целта тук не е да покажем колко знаем. :D

Ето ти пример за полезен празен интерфейс:
Ако трябва да работиш с кода от моя пример, но трябва да изкараш само животните, които могат да летят - ползваш празен интерфейс.

[php]
interface Flyable {}

class Eagle extends Animal implements Flyable {
public function move() {
// Implements flying
}
}

class FlyTest {
public function canFly(Animal $animal) {
if ($animal instanceof Flyable) {
$animal->move();
} else {
// No, this one can't fly...
}
}
}
[/php]

А започнахме с шаблони за дизайн... :D

User avatar
dakata__92
Web-tourist
Web-tourist
Posts: 3260
Joined: Tue Aug 02, 2011 7:24 pm
Answers: 126

Post by dakata__92 » Wed Mar 08, 2017 8:37 pm

pix3l wrote:Лично аз бих използвал абстрактен метод...
Такъв бих използвал и при Animal, докато пишех примера, но не сметнах за нужно да усложнявам, тъй като целта тук не е да покажем колко знаем. :D

Ето ти пример за полезен празен интерфейс:
Ако трябва да работиш с кода от моя пример, но трябва да изкараш само животните, които могат да летят - ползваш празен интерфейс.

[php]
interface Flyable {}

class Eagle extends Animal implements Flyable {
public function move() {
// Implements flying
}
}

class FlyTest {
public function canFly(Animal $animal) {
if ($animal instanceof Flyable) {
$animal->move();
} else {
// No, this one can't fly...
}
}
}
[/php]

А започнахме с шаблони за дизайн... :D
Поправям се за интерфейсите. И празните са полезни. Въпреки, че съм ползвал подобни неща хич не се усетих (изобщо сетих) за този вид структура сега. :D :?: Както и да е. Наистина от къде тръгнахме, та къде стигнахме. Дано автора не ни се сърди за обясненията :P :oops:

pix3l
Нов
Нов
Posts: 161
Joined: Sat Oct 08, 2016 2:31 pm

Post by pix3l » Wed Mar 08, 2017 8:43 pm

Това е техническа дискусия, не говорим празни приказки и всеки може да научи нещо. :D

User avatar
dakata__92
Web-tourist
Web-tourist
Posts: 3260
Joined: Tue Aug 02, 2011 7:24 pm
Answers: 126

Post by dakata__92 » Wed Mar 08, 2017 9:22 pm

pix3l wrote:Това е техническа дискусия, не говорим празни приказки и всеки може да научи нещо. :D
Хехехехе съгласен съм. :?: Веднага драскам код над който автора да се замисли и сам за себе си да си отговори, защо се ползва интерфейса в конкретният случай и с какво той въздейства на класовете extends (наследяващи) Animal. (Нещо като задачка за размисъл му давам) :P

[php]
<?php
interface I
{
public function move($option);
}

abstract class Animal implements I
{
public function move($option)
{
print "<br>".get_called_class()." ".$option;
}
}

class Snake extends Animal
{

}

class Eagle extends Animal
{

}

class Lion extends Animal
{
public function move($option)
{
switch ($option) {
case 1 :
$h = "Runnig Slow";
break;
case 2 :
$h = "Runnig Fast";
break;
default :
$h = "Sleep";
}
print "<br>".get_called_class()." ".$h;
}
}

class Driver
{
public function move($animalName,$option)
{
$err = "";
if (class_exists($animalName)) {
$classAnimal = new $animalName;
if ($classAnimal instanceof I) {
$classAnimal->move($option);
} else {
$err = "Not instance!";
}
} else {
$err = "$animalName no exist!";
}
if (!empty($err)) {
print "<br>".$err;
}
}
}

$driver = new Driver();

$driver->move("Snake","Creeping");
$driver->move("Eagle","Flying");
$driver->move("Lion",1);
$driver->move("Lion",2);
$driver->move("Lion","");
$driver->move("Fish","Swimming");
[/php]

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Post by Revelation » Wed Mar 08, 2017 10:20 pm

За това хората са казали Favor Composition over Inheritance. Но това е advanced тематика, която пак казвам, не е време да научи.

Въпроса е сега да свикне да пише класове с основните принципи, а после сам ще разбира кое къде влиза като полза.

Не става въпрос да му се обясни сингълтон и фактори шаблоните, защото някои шаблони не решават конкретни проблеми. Когато му дойде реда, трябва да се запознае с всеки или поне с повечето. Всеки език набляга на конкретни шаблони, които се използват най-много и са най-полезни.

Нека не му пълним мозъка със странични неща, вместо това да си учи от където учи и ако има конкретен проблем да пита и чак тогава да му се обясни. Безсмислено е да се маже темата с излишни спорове между изграден шаблон по основните концепции и конкретна основна концепция.

И за да поотмажа положението - шаблоните за дизайн се използват умно, а не безразборно. Не значи, че трябва да се използват навсякъде.

chepa
Потребител
Потребител
Posts: 746
Joined: Fri Aug 14, 2009 3:01 pm

Post by chepa » Sun Mar 12, 2017 10:03 am

Дали ще може малко помощ, тъй като го закъсах.. ;д сигурен съм, че е нещо елементарно, но аз не го виждам. Реших да направя Routes по урок, но се мъча вече цял ден без успех и с куп грешки .. Последната, на която се запънах е тази
Fatal error: Cannot declare class Router, because the name is already in use in F:\xampp\htdocs\routers.php on line 9


index.php

[php]
<?php
/**
* Created by PhpStorm.
* User: Melomanchetoo
* Date: 7.3.2017 г.
* Time: 22:58
*/


require 'routers.php';


$router = new Router;

require 'routesPath.php';

$uri = trim($_SERVER['REQUEST_URI'], '/');

var_dump($uri);

require $router -> direct($uri);

[/php]


routesPath.php

[php]
<?php
/**
* Created by PhpStorm.
* User: Melomanchetoo
* Date: 7.3.2017 г.
* Time: 23:07
*/

$router -> define([
'' => 'index.php',
'about' => 'about.php',
'contact' => 'contact.php'
]);
[/php]

routers.php


[php]
<?php

/**
* Created by PhpStorm.
* User: Melomanchetoo
* Date: 7.3.2017 г.
* Time: 22:59
*/
class Router
{

protected $routes = [];
protected $uri;


public function define($routes)
{

$this -> routes = $routes;


}

public function direct($uri)
{

$this -> uri = $uri;

if(array_key_exists($uri, $this->routes)){

return $this -> routes[$uri];


}

}
}

[/php]

User avatar
anonimen
Web-tourist
Web-tourist
Posts: 1562
Joined: Mon Jun 11, 2012 6:07 pm
Answers: 163
Location: Parse error: unexpected "}" in /home/index.php on line 26

Post by anonimen » Sun Mar 12, 2017 11:34 am

Сложи едно echo "Test"; в routers.php за да видиш колко пъти се зарежда този файл. (да не би да го инклудваш втори път някъде другаде)
Пробвай и временно да смениш името, например на Routers, и пробвай пак.

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Post by Revelation » Sun Mar 12, 2017 1:38 pm

Когато извикаш index-а, $_SERVER приема стойността на индекса и де факто се опитваш да рикуарнеш отново индекс и за това ти казва, че вече имаш инстанция на класа.

Когато дефинираш рутера, не трябва да добавяш и index-а, защото той ти играе роля на диспечер.

[php]
<?php
/**
* Created by PhpStorm.
* User: Melomanchetoo
* Date: 7.3.2017 г.
* Time: 22:58
*/


require 'routers.php'; // зареждаш класа


$router = new Router; // правиш инстанция

require 'routesPath.php'; // дефинираш пътищата

$uri = trim($_SERVER['REQUEST_URI'], '/'); // присвояваш index.php

var_dump($uri);

// докато си в index.php се опитваш да заредиш отново
// index.php и в случая кода се наслагва
require $router -> direct($uri);

[/php]
Сложих коментари.

chepa
Потребител
Потребител
Posts: 746
Joined: Fri Aug 14, 2009 3:01 pm

Post by chepa » Sun Mar 12, 2017 8:53 pm

Revelation wrote:Когато извикаш index-а, $_SERVER приема стойността на индекса и де факто се опитваш да рикуарнеш отново индекс и за това ти казва, че вече имаш инстанция на класа.

Когато дефинираш рутера, не трябва да добавяш и index-а, защото той ти играе роля на диспечер.

[php]
<?php
/**
* Created by PhpStorm.
* User: Melomanchetoo
* Date: 7.3.2017 г.
* Time: 22:58
*/


require 'routers.php'; // зареждаш класа


$router = new Router; // правиш инстанция

require 'routesPath.php'; // дефинираш пътищата

$uri = trim($_SERVER['REQUEST_URI'], '/'); // присвояваш index.php

var_dump($uri);

// докато си в index.php се опитваш да заредиш отново
// index.php и в случая кода се наслагва
require $router -> direct($uri);

[/php]
Сложих коментари.
Как би ме посъветвал да го направя?

Post Reply