
“神圣的”代码是一个听起来很冠冕堂皇的词,看起来像是一个黄色标题,但尽管如此,将要讨论的正是这样的代码:它由什么部分组成以及如何编写。 这是一个关于我为确保任务不会随代码审查而返回的事情的故事,并带有以下注释:“ All he * nya-redo”。
我没有专门的教育,我不得不通过错误,擦伤和擦伤的方式在实践中学习编程。 不断努力提高书面代码的质量,我制定了一些应遵循的规则。 我要分享。
GOD的代码-首字母缩写词-根据Grasp,Object健美操,Demeter定律和Solid原理编写的代码。 他们都认识的人,只有一个人见过,但我们将考虑首字母缩略词的每个组成部分。 我的目标不是深入研究每组规则,因为Internet上已多次涉及这些规则。 相反,我根据自己的经验进行了介绍。
格拉斯
九个模板,用于将职责分配给类和对象。 为了方便记忆,我将它们分为两个子组:
- 在第一个子组中,我们可以区分规则,这些规则使您可以编写经过良好测试和修改的原子模块。 这些规则与责任无关,而与模块的特性有关:弱耦合,强粘附力,多态性,抗变化性。 对于我自己,我用SOLID覆盖了这些规则,有关这一点的更多信息,请参见相应部分。
- 第二个子组是更清晰的模板,告诉我们谁创建对象(“创建者”-工厂模式的集合名称),如何减少模块之间的连接(使用“控制器”和“中间”模式)以及委托给谁个人责任(信息专家),以及如果我爱DDD且同时耦合度低(纯小说)怎么办。
在这里阅读更多。
对象健美操
一组代码执行规则,与法律的codeStyle代码非常相似。 也有九个。 我将谈论我在日常工作中尝试遵循的三点(稍作修改),其余的可以在
原始资料中阅读。
- 该方法的长度不超过15个LOC,该类中的方法数量不超过15个,一个名称空间中的类数量不超过15个。最重要的是,很长的代码很难阅读和理解。 另外,长类和方法是违反SRP的信号(更多信息请参见下文)。
- 每个方法最多嵌套一层。
public function processItems(array items)
{
// 0
foreach (items as item) {
// 1
for (i = 0; i < 5; i++) {
// 2
… process item 5 times …
}
}
}
item
.
public function processItems(array items)
{
// 0
foreach (items as item) {
// 1
this.processItem(item);
}
}
public function processItem(Item item)
{
// 0
for (i = 0; i < 5; i++) {
// 1
… process item 5 times …
}
}
-, — , , . else
, .
public function processSomeDto(SomeDtoClass dto)
{
if (predicat) {
throw new Exception(‘predicat is failed’);
} else {
return this.dtoProcessor.process(dto);
}
}
:
public function processSomeDto(SomeDtoClass dto)
{
if (predicat) {
throw new Exception(‘predicat is failed’);
}
return this.dtoProcessor.process(dto);
}
, .
GRASP’a. , .

: B, . . :
- .
- , .
- .
- , .
. , .
this.objectB.objectC.getSomeStuff()
, , .
. -, . :
public function methodA()
{
spawnedObject = this.factory.spawn();
spawnedObject.performSomeStuff();
}
:
public function methodA()
{
this.factory.spawn().performSomeStuff();
}
, - .
public function methodA()
{
this.processor.process(this.factory.spawn());
}
: DTO/Entity. .
public function methodA(SomeDtoClass dto)
{
dto.getAddress().getCity();
}
, , . , , , ,
getCity DTO Address
dto
.
SOLID
SRP, OCP, LSP, ISP, DIP — , .
SRP — . — , . High Cohesion GRASP’a.
: , — - (MVC). - - , SRP.
public function indexAction(RequestInterface request): ResponseInterface
{
requestDto = this.requestTransformer.transform(request);
responseDto = this.requestProcessor.process(requestDto);
return this.responseTransformer.transform(responseDto);
}
- , , — . , , , , .
OCP — -. , , .
- , if/switch. , . . — . , .
resolver, .
final lass Resolver implements ResolverInterface
{
private mapping;
public function Resolver(array mapping)
{
this.mapping = mapping;
}
public function resolve(Item item)
{
return this.mapping[item.getType()].perform(item);
}
}
, . : , final, abstract, .
LSP — . , .
:
- ( ).
- ( , , , ).
- ( ).
- , ( , , , ).
class ParentClass
{
public function someMethod(string param1)
{
// some logic
}
}
class ChildClass extends ParentClass
{
public function someMethod(string param1, string param2)
{
if (param1 == '') {
throw new ExtraException();
}
// some logic
}
}
someMethod
ChildClass
(
param2
),
param1
, . ,
ParentClass
ChildClass
.
ISP — . , . , , , , — , .
interface DuckInterface
{
public function swim(): void;
public function fly(): void;
}
class MallardDuck implements DuckInterface
{
public function swim(): void
{
// some logic
}
public function fly(): void
{
// some logic
}
}
class RubberDuck implements DuckInterface
{
public function swim(): void
{
// some logic
}
public function fly(): void
{
// can't fly :(
}
}
RubberDuck
DuckInterface
. , , ,
DuckInterface
FlyableInterface
SwimableInterface
, .
DIP — . , , ( , ).
new
.
class DIPViolation
{
public function badMethod()
{
someService = new SomeService(445, 'second params');
// operations with someService
}
}
- , . . :
class DIP
{
private $service;
public function DIP(SomeServiceInterface $someService)
{
$this->someService = $someService;
}
public function goodMethod()
{
// operations with someService
}
}
, , , , «» . , . , , , «», , :)