Call Girls In Mukherjee Nagar đą 9999965857 𤊠Delhi đĢĻ HOT AND SEXY VVIP đ SE...
Â
D1 from interfaces to solid
1. Software Architecture & Design
ī¨ Architecture
ī¤ From n-Tier to SOA
ī¤ From SOAP to REST
ī¤ Technical Debt
ī¨ Design
ī¤ From SQL to ORM, NoSQL and ODM
ī¤ From RAD to MVC
ī¤ SOLID principles
ī¤ Domain Driven Design (DDD)
Applying patterns on Delphi code using mORMot
Software Architecture & Design
3. From Interfaces to SOLID
ī¨ Delphi and interfaces
ī¨ SOLID design principles
ī¨ Dependency Injection, stubs and mocks
ī¨ Using mORMot features
ī¨ Delphi and Weak pointers
From Interfaces to SOLID
4. Delphi and interfaces
ī¨ In Delphi OOP model
ī¤ An interface defines a type
that comprises abstract virtual methods
ī¤ It is a declaration of functionality
without an implementation of that functionality
ī¤ It defines "what" is available,
not "how" it is made available
From Interfaces to SOLID
5. Delphi and interfaces
ī¨ Declaring an interface
īŽ Naming convention: ICalculator
īŽ No visibility attribute: all published
īŽ No fields, just methods and properties
īŽ Unique identifier by GUID (Ctrl Shift G)
From Interfaces to SOLID
type
ICalculator = interface(IInvokable)
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
/// add two signed 32 bit integers
function Add(n1,n2: integer): integer;
end;
6. Delphi and interfaces
ī¨ Implementing an interface
īŽ ICalculator added to the âinheritance chainâ
īŽ TCalculator implements a behavior
From Interfaces to SOLID
type
TServiceCalculator = class(TInterfacedObject, ICalculator)
protected
fBulk: string;
public
function Add(n1,n2: integer): integer;
procedure SetBulk(const aValue: string);
end;
function TServiceCalculator.Add(n1, n2: integer): integer;
begin
result := n1+n2;
end;
procedure TServiceCalculator.SetBulk(const aValue: string);
begin
fBulk := aValue;
end;
7. Delphi and interfaces
ī¨ Using an interface
īŽ Strong typing
īŽ The variable defines a behavior (contract)
īŽ Path to abstraction
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
8. Delphi and interfaces
ī¨ Using an interface
īŽ Strong typing
īŽ The variable defines a behavior (contract)
īŽ Path to abstraction
īŽ Automatic try..finally
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: TServiceCalculator;
begin
Calculator := TServiceCalculator.Create;
try
result := Calculator.Add(a,b);
finally
Calculator.Free;
end;
end;
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
9. Delphi and interfaces
ī¨ Automatic try..finally
ī¤ Compiler generates
some hidden codeâĻ
īŽ Behavior inherited from TInterfacedObject
īŽ Similar to COM / ActiveX
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
function MyAdd(a,b: integer): integer;
var Calculator: TServiceCalculator;
begin
Calculator := nil;
Calculator := TServiceCalculator.Create;
try
Calculator.FRefCount := 1;
result := Calculator.Add(a,b);
finally
dec(Calculator.FRefCount);
if Calculator.FRefCount=0 then
Calculator.Free;
end;
end;
10. Delphi and interfaces
ī¨ Interfaces are orthogonal to implementation
ī¤ There is more than one way to do it
From Interfaces to SOLID
type
TOtherServiceCalculator = class(TInterfacedObject, ICalculator)
protected
function Add(n1,n2: integer): integer;
end;
function TOtherServiceCalculator.Add(n1, n2: integer): integer;
begin
result := n2+n1;
end;
function MyOtherAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
ICalculator := TOtherServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
11. SOLID design principles
ī¨ Single responsibility principle
ī¨ Open/closed principle
ī¨ Liskov substitution principle (design by contract)
ī¨ Interface segregation principle
ī¨ Dependency inversion principle
From Interfaces to SOLID
12. SOLID design principles
ī¨ Single responsibility
ī¤ Object should have only a single responsibility
ī¨ Open/closed
ī¤ Entities should be open for extension,
but closed for modification
ī¨ Liskov substitution (design by contract)
ī¤ Objects should be replaceable with instances of their
subtypes without altering the correctness of that program
ī¨ Interface segregation
ī¤ Many specific interfaces are better than one
ī¨ Dependency inversion
ī¤ Depend upon abstractions, not depend upon concretions
From Interfaces to SOLID
13. SOLID design principles
ī¨ Help to fight well-known weaknesses
ī¤ Rigidity
īŽ Hard to change something because every change
affects too many other parts of the system
ī¤ Fragility
īŽ When you make a change, unexpected parts of the
system break
ī¤ Immobility
īŽ Hard to reuse in another application because it cannot
be disentangled from the current application
From Interfaces to SOLID
14. SOLID design principles
ī¨ Single Responsibility
ī¤ When you define a class, it shall be designed to
implement only one feature
ī¤ The so-called feature can be seen as
an "axis of change" or a "a reason for change"
From Interfaces to SOLID
15. SOLID design principles
ī¨ Single Responsibility
ī¤ One class shall have only one reason
that justifies changing its implementation
ī¤ Classes shall have few dependencies
on other classes
ī¤ Classes shall be abstracted
from the particular layer they are running
From Interfaces to SOLID
16. SOLID design principles
ī¨ Single Responsibility
ī¤ Splitting classes
īŽ Imagine a TBarCodeScanner class
to handle a serial bar-code scanner
īŽ Later on, we want to implement USB support
īŽ First idea may be to inherit
From Interfaces to SOLID
17. SOLID design principles
ī¨ Single Responsibility
ī¤ Splitting classes
īŽ Imagine a TBarCodeScanner class
to handle a serial bar-code scanner
īŽ Later on, we want to implement USB support
īŽ But we would rather split the class hierarchy
From Interfaces to SOLID
18. SOLID design principles
ī¨ Single Responsibility
ī¤ Splitting classes
īŽ Later on, the manufacturer updates its protocol
To add new features, e.g. 3D scanning or coffee making
īŽ How do we implement this?
īŽ We have two âaxis of changeâ
so we would define two classes
From Interfaces to SOLID
19. SOLID design principles
ī¨ Single Responsibility
ī¤ Splitting classes
īŽ Later on, the manufacturer updates its protocol
To add new features, e.g. 3D scanning or coffee making
īŽ We defined two classes, which will be joined/composed
in actual barcode scanner classes
From Interfaces to SOLID
20. SOLID design principles
ī¨ Single Responsibility
ī¤ Splitting classes
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
...
constructor TSerialBarCodeScanner.Create(
const aComPort: string; aBitRate: integer);
begin
fConnection := TSerialBarcodeConnection(aComPort,aBitRate);
fProtocol := TBCP1BarcodeProtocol.Create(fConnection);
end;
From Interfaces to SOLID
21. SOLID design principles
ī¨ Single Responsibility
ī¤ Another example
from SynDB class definitions:
īŽ TSQLDBConnectionProperties
īŽ TSQLDBConnection
īŽ TSQLDBStatement
ī¤ Each class has its own purpose,
and axis of change
īŽ And could be implemented via ODBC, OleDB,
direct client accessâĻ
From Interfaces to SOLID
22. SOLID design principles
ī¨ Single Responsibility
ī¤ Do not mix GUI and logic
ī¤ Do not mix logic and database
ī¤ Do not couple your code to an OS
īŽ Check your uses statement
īŽ There should be no reference to the UI
(e.g. Dialogs) in your business class
īŽ No dependency to DB libraries (this is a hard one)
īŽ No reference to WinAPI.Windows
From Interfaces to SOLID
23. SOLID design principles
ī¨ Single Responsibility
ī¤ Code smells
īŽ When abusing of:
FreeAndNil()
{$ifdef} âĻ {$endif}
uses unit1, unit2, unit3, âĻ unit1000;
īŽ When you canât find the right method in a class
īŽ (mORMot may need some refactoring here) ī
īŽ When unitary tests are hard to write
From Interfaces to SOLID
24. SOLID design principles
ī¨ Open / Close principle
ī¤ When you define a class or an interface
īŽ it shall be open for extension
īŽ but closed for modification
From Interfaces to SOLID
25. SOLID design principles
ī¨ Open / Closed principle
ī¤ Open for extension
īŽ Abstract class is overridden by implementations
īŽ No singleton nor global variable â ever
īŽ Rely on abstraction
īŽ if aObject is aClass then âĻ it stinks!
ī¤ Closed for modification
īŽ E.g. via explicitly protected or private members
īŽ RTTI is dangerous: it may open the closed door
From Interfaces to SOLID
26. SOLID design principles
ī¨ Open / Closed principle
ī¤ In practice
īŽ Define meaningful interface types
īŽ Following the Design By Contract principle
īŽ Define Value objects (DTOs) to transfer the data
īŽ With almost no methods, but for initialization
īŽ With public members, to access the value
īŽ Define Process objects to modify the data
īŽ With public methods, abstracted in the interface
īŽ With mostly private members
From Interfaces to SOLID
27. SOLID design principles
ī¨ Open / Close principle
type
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
public
property Protocol: TAbstractBarcodeProtocol read fProtocol;
property Connection: AbstractBarcodeConnection read fConnection;
...
īŽ Protocol and Connection are read/only
īŽ They are injected by the overridden class constructor
īŽ So it will be Open for extension
From Interfaces to SOLID
28. SOLID design principles
ī¨ Open / Close principle
type
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
public
property Protocol: TAbstractBarcodeProtocol read fProtocol;
property Connection: AbstractBarcodeConnection read fConnection;
...
īŽ Protocol and Connection are read/only
īŽ You could not change the behavior of a class
īŽ It is Closed for modification
From Interfaces to SOLID
31. SOLID design principles
ī¨ Liskov substitution principle
ī¤ If TChild is a subtype of TParent
īŽ then objects of type TParent
may be replaced with objects of type TChild
īŽ without altering any of the desirable properties
of that program (correctness, task performed, etc.)
From Interfaces to SOLID
32. SOLID design principles
ī¨ Liskov substitution principle
ī¤ Tied to the Open / Closed principle
īŽ If you define a child, you should not modify the parent
ī¤ Code-reusability of the parent implementation
ī¤ You will be able
to stub or mock an interface or a class
īŽ Allow correct testing of a whole system:
even if all single unit tests did pass,
real system may not work if this principle was broken
From Interfaces to SOLID
33. SOLID design principles
ī¨ Liskov substitution patterns
ī¤ Design by contract
īŽ Meyer's (Eiffel language) rule:
âwhen redefining a routine [in a derivative],
you may only replace its precondition by a weaker
one, and its postcondition by a stronger oneâ
īŽ Define assertions at method level:
īŽ What does it expect, guarantee, and maintain?
īŽ About input/output values or types, side effects,
invariants, errors/exceptions, performanceâĻ
From Interfaces to SOLID
34. SOLID design principles
ī¨ Liskov substitution patterns
ī¤ Write your code using abstract variables
īŽ Rely on parents methods and properties
īŽ Use interface variables
instead of class implementation
īŽ Uncouple dependencies via class composition
From Interfaces to SOLID
35. SOLID design principles
ī¨ Liskov substitution patterns
ī¤ Factory pattern
īŽ In strongly typed languages (Java, C#, Delphi),
the factory is the class/object type and its constructor
ī¤ Repository pattern
īŽ Allow persistence agnosticism (e.g. via ORM)
ī¤ Service locator pattern
īŽ Get a class instance implementing a given interface
īŽ According to the given context (no global/singleton)
From Interfaces to SOLID
36. SOLID design principles
ī¨ Liskov substitution patterns
ī¤ Practical, not dogmatic LSP
īŽ âParentâ and âChildâ are not absolute
īŽ Depending on the context, you may define a given level
as the âhighestâ LSP abstract class
īŽ e.g. if you work on server side, you may need some
server-only properties and methods
īŽ LSP idea is to be consistent,
once the abstraction level is defined
From Interfaces to SOLID
37. SOLID design principles
ī¨ Liskov substitution patterns
ī¤ Practical, not dogmatic LSP
īŽ âParentâ and âChildâ are not absolute
īŽ Inheritance is often used as code sharing among classes,
not as an abstraction contract
īŽ In this context, LSP may not apply at class level:
be pragmatic, and write efficient code
īŽ But LSP may apply at interface level,
for a set of methods implemented by the class
From Interfaces to SOLID
38. SOLID design principles
ī¨ Liskov substitution code smells
if aObject is aClass then âĻ
case aObject.EnumeratedType of âĻ
function âĻ abstract;
without further override;
unit parent;
uses child1,child2,child3;
From Interfaces to SOLID
39. SOLID design principles
ī¨ Interface segregation principle
ī¤ Once an interface has become too 'fat'
it shall be split into smaller
and more specific interfaces
so that any clients of the interface will only know
about the methods that pertain to them
ī¤ In a nutshell, no client should be forced
to depend on methods it does not use
From Interfaces to SOLID
40. SOLID design principles
ī¨ Interface segregation principle
ī¤ Smaller dedicated classes should be preferred
īŽ Single Responsibility Principle
īŽ Favor composition over inheritance
ī¤ Smaller dedicated interfaces
īŽ Gather operations/methods per context
īŽ Meaningful naming and conventions
īŽ So that the contract would be easier to understand
From Interfaces to SOLID
41. SOLID design principles
ī¨ Interface segregation principle
ī¤ Perfectly fits the SOA uncoupling pattern
īŽ Stateless MicroServices for horizontal scaling
ī¤ Allows to release memory and resources ASAP
īŽ Smaller objects have more bounded dependencies
ī¤ Ease unit testing
īŽ Less coverage
īŽ Less coupling
From Interfaces to SOLID
42. SOLID design principles
ī¨ Interface segregation principle
ī¤ Excludes RAD
īŽ Logic implemented in TForm TDataModule
where methods are procedural code in disguise
īŽ Put your logic behind interfaces
and call them from your UI (over VCL and FMX)
ī¤ Favors DDD
īŽ Segregation avoid domain leaking
īŽ Dedicated interfaces, e.g. for third party consumption
From Interfaces to SOLID
43. SOLID design principles
ī¨ Dependency Inversion
ī¤ High-level modules
should not depend on low-level modules
īŽ Both should depend on abstractions
īŽ Following other SOLI principles
ī¤ Abstractions should not depend upon details
īŽ Details should depend upon abstractions
īŽ Business Logic should not depend on database
īŽ Application Layer should not depend on client UI techno
From Interfaces to SOLID
44. SOLID design principles
ī¨ Dependency Inversion
ī¤ In most conventional programming style:
īŽ You write low-level components (e.g. DB tables)
īŽ Then you integrate them with high-level components
ī¤ But this limits the re-use of high-level code
īŽ In fact, it breaks the Liskov substitution principle
īŽ It reduces the testing abilities (e.g. need of a real DB)
From Interfaces to SOLID
45. SOLID design principles
ī¨ Dependency Inversion may be implemented
ī¤ Via a plug-in system
īŽ e.g. external libraries (for embedded applications)
ī¤ Using a service locator
īŽ e.g. SOA catalog (SaaS/cloud)
īŽ class resolution from an interface type
From Interfaces to SOLID
46. SOLID design principles
ī¨ Dependency Inversion may be implemented
ī¤ Via Dependency Injection
īŽ Concretions are injected to the objects using them
īŽ Only abstractions are known at design/coding time
īŽ Uncoupled implementation injected at runtime
īŽ Modular coding
īŽ Perfect for bigger/complex projects, with a set of teams
īŽ Ease testing, via stub/mock dependencies injection
īŽ e.g. a fake database, defined as a Repository service
īŽ Scaling abilities
From Interfaces to SOLID
47. SOLID design principles
ī¨ Dependency Inversion may be implemented
ī¤ Via Dependency Injection
īŽ A class will define its dependencies as read-only
interface members
īŽ Implementation will be injected at constructor level
īŽ via explicit constructor parameters
īŽ via automated resolution via RTTI
īŽ via service locator/resolver
From Interfaces to SOLID
48. DI, Stubs and Mocks
ī¨ Thanks to SOLID design principles
ī¤ All your code logic will now be abstracted
to the implementation underneath
ī¤ But you need to inject the implementation
īŽ This is Dependency Injection purpose
ī¤ You can also create fake instances to implement
a given interface, and enhance testing
īŽ Introducing Stubs and Mocks
From Interfaces to SOLID
49. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Define external dependencies as interface
īŽ as (private / protected) read-only members
ī¤ To set the implementation instance:
īŽ Either inject the interfaces as constructor parameters
īŽ Or use a Factory / Service locator
From Interfaces to SOLID
50. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Purpose is to test the following class:
From Interfaces to SOLID
TLoginController = class(TInterfacedObject,ILoginController)
protected
fUserRepository: IUserRepository;
fSmsSender: ISmsSender;
public
constructor Create(const aUserRepository: IUserRepository;
const aSmsSender: ISmsSender);
procedure ForgotMyPassword(const UserName: RawUTF8);
end;
constructor TLoginController.Create(const aUserRepository: IUserRepository;
const aSmsSender: ISmsSender);
begin
fUserRepository := aUserRepository;
fSmsSender := aSmsSender;
end;
51. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Dependencies are defined as
īŽ Two small, uncoupled, SOLID task-specific interfaces
From Interfaces to SOLID
IUserRepository = interface(IInvokable)
['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}']
function GetUserByName(const Name: RawUTF8): TUser;
procedure Save(const User: TUser);
end;
ISmsSender = interface(IInvokable)
['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}']
function Send(const Text, Number: RawUTF8): boolean;
end;
52. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Using a dedicated Data Transfer Object (DTO)
īŽ No dependency against storage, nor other classes
From Interfaces to SOLID
IUserRepository = interface(IInvokable)
['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}']
function GetUserByName(const Name: RawUTF8): TUser;
procedure Save(const User: TUser);
end;
TUser = record
Name: RawUTF8;
Password: RawUTF8;
MobilePhoneNumber: RawUTF8;
ID: Integer;
end;
53. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ The high-level method to be tested:
īŽ Open/Closed, Liskov and mainly Dependency
Inversion principles are followed
īŽ Will we need a full database and to send a SMS?
From Interfaces to SOLID
procedure TLoginController.ForgotMyPassword(const UserName: RawUTF8);
var U: TUser;
begin
U := fUserRepository.GetUserByName(UserName);
U.Password := Int32ToUtf8(Random(MaxInt));
if fSmsSender.Send('Your new password is '+U.Password,U.MobilePhoneNumber) then
fUserRepository.Save(U);
end;
54. DI, Stubs and Mocks
ī¨ "The Art of Unit Testing" (Osherove, Roy - 2009)
ī¤ Stubs are fake objects
implementing a given contract
and returning pre-arranged responses
īŽ They just let the test pass
īŽ They âemulateâ some behavior (e.g. a database)
From Interfaces to SOLID
55. DI, Stubs and Mocks
ī¨ "The Art of Unit Testing" (Osherove, Roy - 2009)
ī¤ Mocks are fake objects like stubs
which will verify if an interaction occurred or not
īŽ They help decide if a test failed or passed
īŽ There should be only one mock per test
From Interfaces to SOLID
57. DI, Stubs and Mocks
ī¨ Expect â Run â Verify pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
58. DI, Stubs and Mocks
ī¨ Expect â Run â Verify pattern
īŽ TInterfaceStub / TInterfaceMock constructors
are in fact Factories for any interface
īŽ Clear distinction between stub and mock
īŽ Mock is linked to its test case (self: TMyTest)
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
59. DI, Stubs and Mocks
ī¨ Expect â Run â Verify pattern
īŽ Execution code itself sounds like real-life code
īŽ But all dependencies have been injected
īŽ Stubs will emulate real behavior
īŽ Mock will verify that all expectations are fulfilled
From Interfaces to SOLID
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
60. DI, Stubs and Mocks
ī¨ Expect â Run â Verify pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
61. DI, Stubs and Mocks
ī¨ Run â Verify (aka âTest spyâ) pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
Spy: TInterfaceMockSpy;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
Spy := TInterfaceMockSpy.Create(IUserRepository,UserRepository,self);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
Spy.Verify('Save');
end;
62. DI, Stubs and Mocks
ī¨ Another features:
ī¤ Return complex values (e.g. a DTO)
ī¤ Use a delegate to create a stub/mock
īŽ Using named or indexed variant parameters
īŽ Using JSON array of values
ī¤ Access the test case when mocking
ī¤ Trace and verify the calls
īŽ With a fluent interface
īŽ Log all calls (as JSON)
From Interfaces to SOLID
63. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Inheriting from TInjectableObject
type
TServiceToBeTested = class(TInjectableObject,IServiceToBeTested)
protected
fService: IInjectedService;
published
property Service: IInjectedService read fService;
end;
ī¤ Will auto-inject interface published properties
īŽ At instance creation
īŽ Handled by TSQLRest.Services
From Interfaces to SOLID
64. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Inheriting from TInjectableObject
var Test: IServiceToBeTested;
begin
Test := TServiceToBeTested.CreateInjected(
[ICalculator],
[TInterfaceMock.Create(IPersistence,self).
ExpectsCount('SaveItem',qoEqualTo,1),
RestInstance.Services],
[AnyInterfacedObject]);
...
From Interfaces to SOLID
65. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Inheriting from TInjectableObject
procedure TServiceToBeTested.AnyProcessMethod;
var Service: IInjectedService;
begin
Resolve(IInjectedService,Service);
Service.DoSomething;
end;
From Interfaces to SOLID
66. DI, Stubs and Mocks
ī¨ Dependency Injection
ī¤ Inheriting from TInjectableAutoCreateFields
type
TServiceToBeTested = class(TInjectableObjectAutoCreateFields,
IServiceToBeTested)
protected
fService: IInjectedService;
fNestedObject: TSynPersistentValue;
published
property Service: IInjectedService read fService;
property NestedObject: TSynPersistentValue read fNestedObject;
end;
ī¤ Will auto-define published properties
īŽ Resolve interface services
īŽ Create TPersistent TSynPersistent TAutoCreateField
From Interfaces to SOLID
67. Weak references
ī¨ Delphi type reference model
ī¤ class
īŽ as weak references (plain pointer) and explicit Free
īŽ with TComponent ownership for the VCL/FMX
ī¤ integer Int64 currency double record
widestring variant
īŽ with explicit copy
ī¤ string or any dynamic array
īŽ via copy-on-write (COW) with reference counting
ī¤ interface
īŽ as strong reference with reference counting
From Interfaces to SOLID
68. Weak references
ī¨ Strong reference-counted types (OLE/ COM)
ī¤ Will increase the count at assignment
ī¤ And decrease the count at ownerâs release
ī¤ When the count reaches 0, release the instance
ī¨ Issue comes when there are
ī¤ Circular references
ī¤ External list(s) of references
From Interfaces to SOLID
69. Weak references
ī¨ Managed languages (C# or Java)
ī¤ Will let the Garbage Collector handle
interface variable life time
ī¤ This is complex and resource consuming
ī¤ But easy to work with
ī¨ Unmanaged languages (Delphi or ObjectiveC)
ī¤ Need explicit weak reference behavior
ī¤ mORMot features zeroing weak pointers
īŽ Like Appleâs ARC model
From Interfaces to SOLID
70. Weak references
ī¨ Zeroing weak pointers
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
71. Weak references
ī¨ Zeroing weak pointers
This code will leak memory
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
procedure TParent.SetChild(const Value: IChild);
begin
FChild := Value;
end;
procedure TChild.SetParent(const Value: IParent);
begin
FParent := Value;
end;
72. Weak references
ī¨ Zeroing weak pointers
This code wonât leak memory
FChild and FParent will be set to nil
when the stored instance will be freed
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
procedure TParent.SetChild(const Value: IChild);
begin
SetWeakZero(self,@FChild,Value);
end;
procedure TChild.SetParent(const Value: IParent);
begin
SetWeakZero(self,@FParent,Value);
end;
73. Weak references
ī¨ Delphi NextGen memory model
ī¤ Uses ARC for every TObject instance
īŽ This is transparent for TComponent / FMX
īŽ No try âĻ finally Free block needed
īŽ But breaks the proven weak reference model
and a lot of existing code
ī¤ Only UTF-16 string type
īŽ Direct 8 bit string type disabled ī
īŽ UTF8String RawByteString back in 10.1 Berlin ī
From Interfaces to SOLID