开闭原则与策略模式问题
我有几个想法,但我想看看 SO 社区会建议什么。
我有一个抽象类,上面有一个抽象计算方法。我有两个计算不同的实现。这对我来说是策略模式的尖叫,但是其中一个实现要求设置 selected_type 变量,因为它在计算方法内部使用。我想遵循 OCP,因此我的计算方法不应包含依赖项。
该类通过 NHibernate 从数据库中检索,并且在创建对象之后才会设置 selected_type 变量。我试图避免使用 if 语句来设置 selected_type 仅当它是特定实现时。最好的方法是什么?
这是一个代码示例:
public abstract class TagType
{
public virtual long id { get; protected set; }
public virtual string description { get; protected set; }
protected TagType(){}
protected TagType(string description)
{
this.description = description;
}
public abstract decimal Calculate();
}
public class TagTypeImpl1
{
public virtual int tag_months { get; protected set; }
protected TagType() { }
protected TagType(string description, int tag_months): base(description)
{
this.tag_months = tag_months;
}
public override decimal Calculate()
{
return (12*tag_months);
}
}
public class TagTypeImpl2
{
public virtual int tag_months { get; protected set; }
public virtual TagType selected_tag_type { get; protected set; }
protected TagType() { }
protected TagType(string description, int tag_months, TagType selected_tag_type): base(description)
{
this.tag_months = tag_months;
this.selected_tag_type = selected_tag_type;
}
public override decimal Calculate()
{
return selected_tag_type.Calculate() + (12*tag_months);
}
}
public class ConsumerController
{
private readonly IRepository<TagType> repository;
public ConsumerController(IRepository<TagType> repository)
{
this.repository = repository;
}
public ActionResult Index(long id)
{
var tag_type = repository.get(id);
//If using TagTypeImpl2 then the selected_tag_type variable needs to be set
//I want to avoid if(tag_type.GetType() == typeof(TagTypeImpl2)) set selected_tag_type
var result = tag_type.Calculate();
return Json(new {result});
}
}
我可能试图对这个类做太多事情,并且持久化实体类可能不是放置计算方法的地方,但它似乎是最好的地方,因为它最了解如何进行计算。
I have a couple of ideas but I wanted to see what the SO community would suggest.
I have an abstract class with an abstract Calculate method on it. I have 2 implementations of it that calculate differently. This screams Strategy pattern to me however one of the implementations requires that a selected_type variable be set because it is used inside the Calculate method. I want to follow the OCP so my Calculate method shouldn't take in the dependencies.
This class is retrieved from the DB via NHibernate and the selected_type variable won't be set until after the object has been created. I'm trying to avoid an if statement to set the selected_type only if it is of a specific implementation. What would be the best way?
Here is a code example:
public abstract class TagType
{
public virtual long id { get; protected set; }
public virtual string description { get; protected set; }
protected TagType(){}
protected TagType(string description)
{
this.description = description;
}
public abstract decimal Calculate();
}
public class TagTypeImpl1
{
public virtual int tag_months { get; protected set; }
protected TagType() { }
protected TagType(string description, int tag_months): base(description)
{
this.tag_months = tag_months;
}
public override decimal Calculate()
{
return (12*tag_months);
}
}
public class TagTypeImpl2
{
public virtual int tag_months { get; protected set; }
public virtual TagType selected_tag_type { get; protected set; }
protected TagType() { }
protected TagType(string description, int tag_months, TagType selected_tag_type): base(description)
{
this.tag_months = tag_months;
this.selected_tag_type = selected_tag_type;
}
public override decimal Calculate()
{
return selected_tag_type.Calculate() + (12*tag_months);
}
}
public class ConsumerController
{
private readonly IRepository<TagType> repository;
public ConsumerController(IRepository<TagType> repository)
{
this.repository = repository;
}
public ActionResult Index(long id)
{
var tag_type = repository.get(id);
//If using TagTypeImpl2 then the selected_tag_type variable needs to be set
//I want to avoid if(tag_type.GetType() == typeof(TagTypeImpl2)) set selected_tag_type
var result = tag_type.Calculate();
return Json(new {result});
}
}
I might be trying to do too much with this class adn maybe the persisted entity class is the wrong place to have the Calculate method but it seemed the best place since it knows the most about how to do the calculation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
决定策略需要什么不是你的班级的责任,而是策略的责任。整个想法是,您可以始终以相同的方式调用您正在使用的任何策略。
只需让所有策略实现相同的接口(包括 selected_type),但其中一个策略忽略 selected_type,另一个则使用它。这由策略本身决定。
或者,您的策略实现可以具有比接口中定义的属性更多的属性。如果您可以从类外部初始化策略,并且初始化类了解有关特定实现的更多信息不是问题,那么您可以仅为需要它的特定策略设置属性。前一个解决方案虽然更干净(始终使用相同的界面)。
It's not the responsibility of your class to decide what the strategies need, it's the responsibility of the strategy. The whole idea is that you can call whatever strategy you're using the same way, all the time.
Simply make all strategies implement the same interface -including selected_type-, but one of them ignores the selected_type, the other uses it. It's up to the strategy itself to decide this.
Alternatively, your implementations of strategy can have more properties than are defined in the interface. If you can initialize the strategies from outside of your class, and it's not a problem for the initializing class to know more about the specific implementation you might be able to set the properties for only the specific strategy that needs it. The former solution is cleaner though (always using the same interface).
创建一个虚拟(可重写)函数“Initialize”是否有意义,该函数应该调用从存储库加载的所有 tag_type 对象,以便它们可以执行默认构造函数跳过的参数化构造函数会执行的操作?
或者您可以更改默认构造函数以将 selected_type 初始化为正确的值或指示计算方法在使用之前进行更正的某个值吗?
Would it make sense to create a virtual (overridable) function "Initialize" that one should call on all tag_type objects loaded from repository so they can do what was skipped by the default constructor that the parameterized constructor would have done?
Or can you change the default constructor to initialize selected_type to either the correct value or some value that will instruct the calculate method to correct it before using it?