Design patterns 我怎样才能拥有一个遵循开闭原则的行为丰富的领域实体?

Design patterns 我怎样才能拥有一个遵循开闭原则的行为丰富的领域实体?,design-patterns,domain-driven-design,open-closed-principle,Design Patterns,Domain Driven Design,Open Closed Principle,各国: 软件实体(类、模块、函数等)应开放以进行扩展,但应关闭以进行修改 我现在正在设计一个域,并且在我的域实体中包含了相当多的行为。我正在使用域事件并将依赖项注入到方法中,以确保我的实体不会受到外部影响。然而,我突然想到,如果客户端以后想要更多的功能,我将不得不违反OCP并打开这些域实体来添加功能。一个行为丰富的领域实体如何与开闭原则和谐共存?在设计类时,牢记开闭原则(OCP)是很有用的,但立即将类“关闭以进行修改”并不总是实用或可取的。我认为单一责任原则(SRP)在实践中更有用——只要一个类

各国:

软件实体(类、模块、函数等)应开放以进行扩展,但应关闭以进行修改


我现在正在设计一个域,并且在我的域实体中包含了相当多的行为。我正在使用域事件并将依赖项注入到方法中,以确保我的实体不会受到外部影响。然而,我突然想到,如果客户端以后想要更多的功能,我将不得不违反OCP并打开这些域实体来添加功能。一个行为丰富的领域实体如何与开闭原则和谐共存?

在设计类时,牢记开闭原则(OCP)是很有用的,但立即将类“关闭以进行修改”并不总是实用或可取的。我认为单一责任原则(SRP)在实践中更有用——只要一个类只做一件事,如果对这件事的需求发生变化,就可以修改它


而且,随着时间的推移,SRP会导致OCP;如果您发现自己经常更改一个类,您最终会对其进行重构,以便将更改部分隔离在一个单独的类中,从而使原始类更加封闭。

答案很简单:工厂方法和接口+组合

Open for extension意味着您可以使用新的子类添加新功能

要启用该功能,您必须使用工厂来创建域对象。我通常将我的存储库用作工厂

如果您针对接口而不是具体对象编写代码,则可以轻松添加新功能:

  • 尤瑟
  • IManager:IUser(添加一些管理器功能)
  • ISupervisor:IUser(添加管理器功能)
功能本身可以是小类,您可以使用组合将其包括在内:

public class ManagerSupervisor : User, IManager, ISupervior
(
    public ManagerSupervisor()
    {
        // used to work with the supervisor features.
        // without breaking Law Of Demeter
        _supervisor = new SuperVisorFeatures(this);

    }
)

这是一个很难解释的问题,没有具体的例子。我建议您阅读Robert Martin的书《敏捷软件开发、原则、模式和实践》。这本书也是开闭原则的来源

具有丰富行为的域对象与开闭原则不冲突。如果他们没有行为,您就无法创建合理的扩展。应用开放-关闭原则的关键是预测未来的变化,创建新的接口来履行角色,并使其保持单一责任

我将讲述一个在实际代码中应用开闭原则的故事。希望能有帮助

我有一个Sender类,它一开始就发送消息:

package com.thinkinginobjects;

public class MessageSender {

private Transport transport;

public void send(Message message) {
    byte[] bytes = message.toBytes();
    transport.sendBytes(bytes);
}
}
有一天,我被要求发送10条信息。一个简单的解决办法是:

包com.thinkingobjects

公共类MessageSenderWithBatch{

private static final int BATCH_SIZE = 10;

private Transport transport;

private List<Message> buffer = new ArrayList<Message>();

public void send(Message message) {
    buffer.add(message);
    if (buffer.size() == BATCH_SIZE) {
        for (Message each : buffer) {
            byte[] bytes = each.toBytes();
            transport.sendBytes(bytes);
        }
                    buffer.clear();
    }
}
}
private static final int BATCH\u SIZE=10;
私人运输;
私有列表缓冲区=新的ArrayList();
公共无效发送(消息){
buffer.add(消息);
if(buffer.size()=批处理大小){
对于(每个消息:缓冲区){
byte[]bytes=each.toBytes();
transport.sendBytes(字节);
}
buffer.clear();
}
}
}
然而,我的经验告诉我,这可能不是故事的结局。我预计人们将需要不同的批量处理消息的方式。因此,我创建了一个批处理策略,并让我的发件人使用它注意,我在这里应用了开-关原则。如果我将来有新的批处理策略,我的代码是开放的(通过添加新的批处理策略),但接近修改(通过不修改任何现有代码)。然而,正如Robert Martin在他的书中所说,当代码对某些类型的更改开放时,它也接近于其他类型的更改。如果有人希望在将来发送后通知组件,则我的代码不适用于此类更改

package com.thinkinginobjects;

public class MessageSenderWithStrategy {

private Transport transport;

private BatchStrategy strategy;

public void send(Message message) {
    strategy.newMessage(message);
    List<Message> messages = strategy.getMessagesToSend();

    for (Message each : messages) {
        byte[] bytes = each.toBytes();
        transport.sendBytes(bytes);
    }
    strategy.sent();
}
}

package com.thinkinginobjects;

public class FixSizeBatchStrategy implements BatchStrategy {

private static final int BATCH_SIZE = 0;
private List<Message> buffer = new ArrayList<Message>();

@Override
public void newMessage(Message message) {
    buffer.add(message);    
}

@Override
public List<Message> getMessagesToSend() {
    if (buffer.size() == BATCH_SIZE) {
        return buffer;
    } else {
        return Collections.emptyList();
    }
}

@Override
public void sent() {
    buffer.clear(); 
}

}
package com.thinkingingobjects;
公共类MessageSenderWithStrategy{
私人运输;
民营企业战略;
公共无效发送(消息){
策略。新消息(消息);
List messages=strategy.getMessagesToSend();
对于(每条消息:消息){
byte[]bytes=each.toBytes();
transport.sendBytes(字节);
}
策略。发送();
}
}
包com.thinkingobjects;
公共类FixSizeBatchStrategy实现了BatchStrategy{
私有静态最终整数批大小=0;
私有列表缓冲区=新的ArrayList();
@凌驾
公共无效新消息(消息消息){
buffer.add(消息);
}
@凌驾
公共列表getMessagesToSend(){
if(buffer.size()=批处理大小){
返回缓冲区;
}否则{
返回集合。emptyList();
}
}
@凌驾
公开作废发送(){
buffer.clear();
}
}
为了完成这个故事,我在几天后收到一个要求,每5秒发送一次批量消息。我的猜测是对的,我可以通过添加扩展而不是修改代码来满足需求:

package com.thinkinginobjects;

public class FixIntervalBatchStrategy implements BatchStrategy {

private static final long INTERVAL = 5000;

private List<Message> buffer = new ArrayList<Message>();

private volatile boolean readyToSend;

public FixIntervalBatchStrategy() {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.scheduleAtFixedRate(new Runnable() {

        @Override
        public void run() {
            readyToSend = true;

        }
    }, 0, INTERVAL, TimeUnit.MILLISECONDS);
}

@Override
public void newMessage(Message message) {
    buffer.add(message);
}

@Override
public List<Message> getMessagesToSend() {
    if (readyToSend) {
        return buffer;
    } else {
        return Collections.emptyList();
    }
}

@Override
public void sent() {
    readyToSend = false;
    buffer.clear();
}
}
package com.thinkingingobjects;
公共类FixIntervalBatchStrategy实现BatchStrategy{
专用静态最终长间隔=5000;
私有列表缓冲区=新的ArrayList();
私有易失布尔readyToSend;
公共FixIntervalBatchStrategy(){
ScheduledExecutorService executorService=Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(新的Runnable(){
@凌驾
公开募捐{
readyToSend=true;
}
},0,间隔,时间单位为毫秒);
}
@凌驾
公共无效新消息(消息消息){
buffer.add(消息);
}
@凌驾
公共列表getMessagesToSend(){
如果(readyToSend){
返回缓冲区;
}否则{
返回集合。emptyList();
}
}
@凌驾
公开作废发送(){
readyToSend=false;
buffer.clear();
}
}
  • 免责声明:代码示例属于www.thinkingInObjects.com
您现在在