Documente Academic
Documente Profesional
Documente Cultură
RAPORT
A efectuat :
A verificat:
Chișinău 2013
2
1. Scopul lucrării
Studierea șabloanelor de proiectare creaționale.
2. Sarcina lucrării
De realizat o aplicație utilizând șabloanele creaționale Abstract Factory, Factory Method, Builder,
Prototype și Singleton.
Abstract Factory
- Oferă o interfață pentru a crea familii de obiecte înrudite sau dependente fără a fi nevoiți
să specificăm clasa concretă;
- Oferă o ierarhie care încapsulează mai multe platforme posibile și posibilitatea de a
construi o suită de produse;
- Operatorul new devine dăunator în instanțiere (nu se mai face direct).
În figura 3.1 este prezentată diagrama de clase pentru șablonul de proiectare Abstract Factory.
3
Figura 3.1. Diagrama de clase pentru șablonul de proiectare Abstract Factory
Factory Method
- Definește o interfață de creare a unui obiect dar lasă clasele derivate (subclasele) să
decidă cum instanțiază obiectul. Factory Method lasă o clasă să cedeze modul de
instanțiere a subclaselor;
- Se definește un constructor “virtual”;
- Operatorul new devine dăunător, inutil;
- Exemplu de necesitate a acestui pattern: un framework trebuie să standardizeze modelul
arhitectural pentru o varietate mare de aplicații dar să permită aplicațiilor individuale să-
și definească propriile obiecte și să le implementeze modul de instanțiere.
Diagrama de clase pentru șablonul de proiectare Factory Method este prezentată în figura 3.2.
Prototype
- Specifică tipurile de obiecte ce se pot crea utilizând o instanță “prototip” și crează obiecte
noi copiind acest prototip;
- Se evită subclasele unui obiect “creator” în aplicația client, la fel cum face și abstract
factory;
- Evită costul crescut al creării unui obiect nou în modul standard (utilizând operatorul
new) când aceasta este foarte costisitoare și scumpă pentru o aplicație dată.
- Pentru a implementa acest pattern, se declară o clasă abstractă de bază care specifică o
metodă virtuală pura clone(). Orice clasă care este derivată din clasa de bază
implementează metoda clone().
- Clientul, în loc să scrie cod care invocă operatorul new, apelează metoda clone() a
prototipului sau apelează o metodă factory cu un parametru specificând clasa derivată
dorită.
Diagrama de clase pentru șablonul de proiectare Prototype este prezentată în figura 3.4.
5
Figura 3.4. Diagrama de clase pentru șablonul de proiectare Prototype
Singleton
- Modelul de proiectare singleton este un model creațional ce asigură faptul că avem o
singură instanță a unei clase particulare în timpul rulării programului și ne oferă un punct
global de acces la această singură instanță.
- Mecanismul prin care este posibilă impunerea unei singure clase este realizat prin
definirea constructorului clasei respective ca privat și furnizarea unei metode (care se
numește metodă singleton) care este apelată în momentul în care se dorește instanțierea.
Aceasta va verifica numărul de instanțe și va controla procesul de instanțiere.
Diagrama de clase pentru șablonul de proiectare Singleton este prezentată în figura 3.5.
4. Realizarea sarcinii
6
Aplicația creată utilizând cele 5 șabloane de proiectare creaționale enunțate este un mini-joc în
care utilizatorul poate deplasa în stânga și în dreapta un jucător și poate “împușca” în sus, iar din sus în
jos vin inamicii care trebuie împușcați înainte de a ajunge jos. Atunci când unul din inamici ajunge jos,
jocul se termină. Pentru fiecare unitate de daună adusă inamicului, jucătorul primește câte un punct.
Atunci când utilizatorul începe un joc nou, el are de ales între a juca cu un jucător rapid sau cu
un jucător puternic. La jucătorul rapid patroanele zboară mai repede, însă produc mai puține pagube
inamicilor. Cel puternic are niște patroane care se mișcă mai încet, însă acestea sunt mai mari ca
dimensiuni și produc daune mai mari inamicilor.
Inamicii sunt și ei de 2 tipuri: de formă dreptunghiulară și mai ușor de ucis și de forma unei
elipse și mai dificil de ucis.
Se observă că un anumit tip de jucător este legat de un anumit tip de patron. Aici vine în ajutor
șablonul de proiectare AbstractFactory. Clasa PlayerAbstractFactory definește 2 metode:
CreateBullet() pentru crearea unui patron și CreatePlayer() pentru crearea jucătorului. Fabricile
concrete QuickPlayerFactory și StrongPlayerFactory implementează cele 2 metode pentru a crea tipuri
concrete ale clase Player, respectiv Bullet. Se observă, deci, și utilizarea șablonului Factory Method, în
care clasa de bază lasă clasele derivate să instanțieze obiecte concrete.
Deoarece pe parcursul jocului se crează multe patroane, am ales șablonul de proiectare Prototype
pentru instanțierea lor. Clasa Bullet, deci, definește metoda abstractă Clone() care este implementată de
clasele derivate. Mai este utilizată o clasă PrototypeManager care menține și gestionează prototipurile,
adică obiectele concrete care sunt clonate pentru a obține instanțe noi.
Clasa GameInfo menține și gestionează informațiile despre starea jocului, cum ar fi poziția
jucătorului, patroanele, inamicii. Funcția Change din această clasă realizează trecerea dintr-o stare a
jocului în următoarea stare, adică mișcarea inamicilor și a patroanelor și detectarea coliziunilor între
acestea.
Diagrama de clase ce prezintă cele expuse este prezentată în figura 4.1.
7
Figura 4.1. Prima diagramă de clase
Clasa GameInfo are o instanță păstrată într-o altă clasă – clasa Game. Această clasă pune la
dispoziție metode pentru pornirea și oprirea jocului, dar și obținerea diferitor informați despre starea
jocului prin accesarea instanței clasei GameInfo.
Clasa Game implementează șablonul de proiectare Singleton, deoarece există un singur joc și e
necesar să avem un punct global de acces la instanța jocului.
Clasa GameInfo este relativ complexă, fiind compusă din mai multe obiecte, din această cauză
pentru instanțierea ei a fost utilizat șablonul de proiectare Builder. Părțile create sunt fabrica
PlayerAbstractFactory, jucătorul Player și PrototypeManager-ul.
Diagrama de clase care ilustrează șabloanele enumerate este prezentată în figura 4.2.
8
Figura 4.2. A doua diagramă de clase
Pentru reprezentarea unui inamic mai este definită o clasă numită Enemy. Aici, la fel ca și în
cazul clasei Bullet, este utilizat șablonul de proiectare Prototype. Cele 2 clase derivate de la clasa
Enemy – HardEnemy și EasyEnemy implementează metoda Clone() din clasa părinte pentru a realiza
clonarea obiectelor.
Diagrama care include și clasele ce reprezintă inamicii este prezentată în figura 4.3. Codul sursă
poate fi găsit în anexa B. În anexa A poate fi găsit un screenshot de la execuția programului.
9
Figura 4.3. A treia diagramă de clase
Concluzii
La această lucrare de laborator am studiat șabloanele creaționale de proiectare. Aceste șabloane
au o mare importanță, mai ales în cazul unor proiecte mai mari, deoarece ele fac sistemul independent
de modul în care sunt create obiectele. Aceasta permite crearea unor aplicațiile flexibile, ce pot fi
modificate mai ușor.
10
Anexa A. Screenshot de la execuția aplicației
11
Anexa B. Codul sursă al aplicației
Bullet.cs
using System.Drawing;
ConcreteGameInfoBuilder.cs
public class ConcreteGameInfoBuilder : GameInfoBuilder
{
private GameInfo gameInfo;
EasyEnemy.cs
using System.Drawing;
Enemy.cs
using System.Drawing;
Form1.cs
using System;
using System.Windows.Forms;
namespace SpaceInvaders
{
public partial class Form1 : Form
{
Game game = Game.GetInstance();
int dir = 0;
bool shooting = false;
public Form1()
{
InitializeComponent();
}
13
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (!game.IsConstructed()) return;
game.GetGameInfo().GetPlayer().Draw(e.Graphics);
foreach (var b in game.GetGameInfo().GetBullets()) b.Draw(e.Graphics);
foreach (var en in game.GetGameInfo().GetEnemies()) en.Draw(e.Graphics);
}
Game.cs
public class Game
{
private GameInfo gameInfo;
private static Game instance;
public ConcreteGameInfoBuilder builder;
public bool started = false;
public bool constructed = false;
private Game() { }
GameInfo.cs
using System;
using System.Collections.Generic;
using System.Drawing;
15
public bool Change() {
bool colesion = false;
for (int i = 0; i < enemies.Count; i++) enemies[i].MoveDown(2);
for (int i = 0; i < bullets.Count; )
{
bullets[i].MoveUp();
colesion = false;
for (int j = 0; j < enemies.Count; j++)
if (bullets[i].GetR().IntersectsWith(enemies[j].GetR()))
{
score += Math.Min(bullets[i].GetForce(), enemies[j].GetHealth());
enemies[j].DecreaseHealth(bullets[i].GetForce());
bullets.RemoveAt(i);
if (enemies[j].GetHealth() <= 0) enemies.RemoveAt(j);
colesion = true;
break;
}
if (!colesion) i++;
}
GenerateRandomEnemies();
for (int i = 0; i < bullets.Count; )
{
if (bullets[i].GetR().Y < -bullets[i].GetR().Height)
bullets.RemoveAt(i);
else i++;
}
for (int i = 0; i < enemies.Count; i++)
if (enemies[i].GetR().Y > 350) return false;
return true;
}
16
public int GetScore() { return score; }
GameInfoBuilder.cs
public interface GameInfoBuilder
{
void BuildPlayer();
void BuildPlayerFactory(PlayerAbstractFactory playerFactory);
void BuildPrototypeManager();
}
HardEnemy.cs
using System.Drawing;
Player.cs
using System.Drawing;
17
public void MoveRight(int dx) { r.X += dx; }
}
PlayerAbstractFactory.cs
public interface PlayerAbstractFactory
{
Bullet CreateBullet();
Player CreatePlayer();
}
PrototypeManager.cs
using System;
using System.Collections.Generic;
QuickBullet.cs
using System.Drawing;
public QuickBullet(QuickBullet b)
{
Rectangle br = b.GetR();
r = new Rectangle(br.X, br.Y, br.Width, br.Height);
speed = b.speed;
force = b.force;
18
}
QuickPlayer.cs
using System.Drawing;
QuickPlayerFactory.cs
public class QuickPlayerFactory : PlayerAbstractFactory {
public Bullet CreateBullet(){
return new QuickBullet();
}
StrongBullet.cs
using System.Drawing;
public StrongBullet(StrongBullet b)
{
Rectangle br = b.GetR();
r = new Rectangle(br.X, br.Y, br.Width, br.Height);
speed = 5;
force = 2;
}
StrongPlayer.cs
using System.Drawing;
StrongPlayerFactory.cs
public class StrongPlayerFactory : PlayerAbstractFactory {
public Bullet CreateBullet()
{
return new StrongBullet();
}
20